@langchain/langgraph 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/channels/base.cjs +10 -3
  2. package/dist/channels/base.cjs.map +1 -1
  3. package/dist/channels/base.d.cts.map +1 -1
  4. package/dist/channels/base.d.ts.map +1 -1
  5. package/dist/channels/base.js +10 -3
  6. package/dist/channels/base.js.map +1 -1
  7. package/dist/channels/binop.cjs +2 -1
  8. package/dist/channels/binop.cjs.map +1 -1
  9. package/dist/channels/binop.d.cts.map +1 -1
  10. package/dist/channels/binop.d.ts.map +1 -1
  11. package/dist/channels/binop.js +2 -1
  12. package/dist/channels/binop.js.map +1 -1
  13. package/dist/errors.cjs +22 -0
  14. package/dist/errors.cjs.map +1 -1
  15. package/dist/errors.d.cts +10 -1
  16. package/dist/errors.d.cts.map +1 -1
  17. package/dist/errors.d.ts +10 -1
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +21 -1
  20. package/dist/errors.js.map +1 -1
  21. package/dist/graph/messages_reducer.cjs +23 -6
  22. package/dist/graph/messages_reducer.cjs.map +1 -1
  23. package/dist/graph/messages_reducer.d.cts +4 -2
  24. package/dist/graph/messages_reducer.d.cts.map +1 -1
  25. package/dist/graph/messages_reducer.d.ts +4 -2
  26. package/dist/graph/messages_reducer.d.ts.map +1 -1
  27. package/dist/graph/messages_reducer.js +24 -7
  28. package/dist/graph/messages_reducer.js.map +1 -1
  29. package/dist/index.cjs +2 -0
  30. package/dist/index.d.cts +2 -2
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +2 -2
  33. package/dist/interrupt.cjs +9 -1
  34. package/dist/interrupt.cjs.map +1 -1
  35. package/dist/interrupt.d.cts.map +1 -1
  36. package/dist/interrupt.d.ts.map +1 -1
  37. package/dist/interrupt.js +10 -2
  38. package/dist/interrupt.js.map +1 -1
  39. package/dist/pregel/debug.cjs +1 -0
  40. package/dist/pregel/debug.cjs.map +1 -1
  41. package/dist/pregel/debug.js +1 -0
  42. package/dist/pregel/debug.js.map +1 -1
  43. package/dist/pregel/loop.cjs +15 -8
  44. package/dist/pregel/loop.cjs.map +1 -1
  45. package/dist/pregel/loop.js +15 -8
  46. package/dist/pregel/loop.js.map +1 -1
  47. package/dist/pregel/runner.cjs +1 -1
  48. package/dist/pregel/runner.cjs.map +1 -1
  49. package/dist/pregel/runner.js +2 -2
  50. package/dist/pregel/runner.js.map +1 -1
  51. package/dist/web.cjs +2 -0
  52. package/dist/web.d.cts +2 -2
  53. package/dist/web.d.ts +2 -2
  54. package/dist/web.js +2 -2
  55. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { initializeAsyncLocalStorageSingleton } from "./node.js";
2
2
  import { COMMAND_SYMBOL, Command, CommandInstance, END, INTERRUPT, Overwrite, START, Send, isCommand, isInterrupted } from "./constants.js";
3
- import { BaseLangGraphError, EmptyChannelError, EmptyInputError, GraphBubbleUp, GraphDrained, GraphInterrupt, GraphRecursionError, GraphValueError, InvalidUpdateError, MultipleSubgraphsError, NodeError, NodeInterrupt, NodeTimeoutError, ParentCommand, RemoteException, StateGraphInputError, UnreachableNodeError, getSubgraphsSeenSet, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isNodeError, isNodeTimeoutError, isParentCommand } from "./errors.js";
3
+ import { BaseLangGraphError, EmptyChannelError, EmptyInputError, GraphBubbleUp, GraphDrained, GraphInterrupt, GraphRecursionError, GraphValueError, InvalidUpdateError, MultipleSubgraphsError, NodeError, NodeInterrupt, NodeTimeoutError, ParentCommand, RemoteException, StateGraphInputError, UnreachableNodeError, _markInvalidResume, getSubgraphsSeenSet, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isInvalidResume, isNodeError, isNodeTimeoutError, isParentCommand } from "./errors.js";
4
4
  import { BaseChannel } from "./channels/base.js";
5
5
  import { BinaryOperatorAggregate } from "./channels/binop.js";
6
6
  import { Annotation } from "./graph/annotation.js";
@@ -37,6 +37,6 @@ import { AsyncBatchedStore, BaseCheckpointSaver, BaseStore, InMemoryStore, Memor
37
37
  //#region src/index.ts
38
38
  initializeAsyncLocalStorageSingleton();
39
39
  //#endregion
40
- export { Annotation, AsyncBatchedStore, BaseChannel, BaseCheckpointSaver, BaseLangGraphError, BaseStore, BinaryOperatorAggregate, COMMAND_SYMBOL, ChatModelStreamImpl, Command, CommandInstance, CompiledStateGraph, DeltaChannel, DeltaValue, END, EmptyChannelError, EmptyInputError, StreamChannel as EventLog, Graph, GraphBubbleUp, GraphCallbackHandler, GraphDrained, GraphInterrupt, GraphRecursionError, GraphRunStream, GraphValueError, INTERRUPT, InMemoryStore, InvalidUpdateError, MemorySaver, MessageGraph, MessagesAnnotation, MessagesDeltaValue, MessagesValue, MessagesZodMeta, MessagesZodState, MultipleSubgraphsError, NodeError, NodeInterrupt, NodeTimeoutError, Overwrite, ParentCommand, REMOVE_ALL_MESSAGES, ReducedValue, RemoteException, RunControl, START, STREAM_EVENTS_V3_MODES, Send, StateGraph, StateGraphInputError, StateSchema, StreamChannel, SubgraphRunStream, UnreachableNodeError, UntrackedValue, UntrackedValueChannel, messagesStateReducer as addMessages, convertToProtocolEvent, copyCheckpoint, createGraphRunStream, createLifecycleTransformer, createMessagesTransformer, createSubgraphDiscoveryTransformer, createValuesTransformer, emptyCheckpoint, entrypoint, filterLifecycleEntries, filterSubgraphHandles, getConfig, getCurrentTaskInput, getJsonSchemaFromSchema, getPreviousState, getSchemaDefaultGetter, getStore, getSubgraphsSeenSet, getWriter, interrupt, isCheckpointEnvelope, isCommand, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isInterrupted, isNativeTransformer, isNodeError, isNodeTimeoutError, isParentCommand, isSerializableSchema, isStandardSchema, messagesDeltaReducer, messagesStateReducer, pushMessage, task, writer };
40
+ export { Annotation, AsyncBatchedStore, BaseChannel, BaseCheckpointSaver, BaseLangGraphError, BaseStore, BinaryOperatorAggregate, COMMAND_SYMBOL, ChatModelStreamImpl, Command, CommandInstance, CompiledStateGraph, DeltaChannel, DeltaValue, END, EmptyChannelError, EmptyInputError, StreamChannel as EventLog, Graph, GraphBubbleUp, GraphCallbackHandler, GraphDrained, GraphInterrupt, GraphRecursionError, GraphRunStream, GraphValueError, INTERRUPT, InMemoryStore, InvalidUpdateError, MemorySaver, MessageGraph, MessagesAnnotation, MessagesDeltaValue, MessagesValue, MessagesZodMeta, MessagesZodState, MultipleSubgraphsError, NodeError, NodeInterrupt, NodeTimeoutError, Overwrite, ParentCommand, REMOVE_ALL_MESSAGES, ReducedValue, RemoteException, RunControl, START, STREAM_EVENTS_V3_MODES, Send, StateGraph, StateGraphInputError, StateSchema, StreamChannel, SubgraphRunStream, UnreachableNodeError, UntrackedValue, UntrackedValueChannel, _markInvalidResume, messagesStateReducer as addMessages, convertToProtocolEvent, copyCheckpoint, createGraphRunStream, createLifecycleTransformer, createMessagesTransformer, createSubgraphDiscoveryTransformer, createValuesTransformer, emptyCheckpoint, entrypoint, filterLifecycleEntries, filterSubgraphHandles, getConfig, getCurrentTaskInput, getJsonSchemaFromSchema, getPreviousState, getSchemaDefaultGetter, getStore, getSubgraphsSeenSet, getWriter, interrupt, isCheckpointEnvelope, isCommand, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isInterrupted, isInvalidResume, isNativeTransformer, isNodeError, isNodeTimeoutError, isParentCommand, isSerializableSchema, isStandardSchema, messagesDeltaReducer, messagesStateReducer, pushMessage, task, writer };
41
41
 
42
42
  //# sourceMappingURL=index.js.map
@@ -59,7 +59,15 @@ function interrupt(value, options) {
59
59
  if (!conf) throw new Error("No configurable found in config");
60
60
  if (!conf["__pregel_checkpointer"]) throw new require_errors.GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
61
61
  const schema = options?.responseSchema;
62
- const parseResume = (resume) => schema !== void 0 && (0, _langchain_core_utils_types.isInteropZodSchema)(schema) ? (0, _langchain_core_utils_types.interopParse)(schema, resume) : resume;
62
+ const parseResume = (resume) => {
63
+ if (schema === void 0 || !(0, _langchain_core_utils_types.isInteropZodSchema)(schema)) return resume;
64
+ try {
65
+ return (0, _langchain_core_utils_types.interopParse)(schema, resume);
66
+ } catch (error) {
67
+ require_errors._markInvalidResume(error);
68
+ throw error;
69
+ }
70
+ };
63
71
  const scratchpad = conf[require_constants.CONFIG_KEY_SCRATCHPAD];
64
72
  scratchpad.interruptCounter += 1;
65
73
  const idx = scratchpad.interruptCounter;
@@ -1 +1 @@
1
- {"version":3,"file":"interrupt.cjs","names":["AsyncLocalStorageProviderSingleton","GraphValueError","CONFIG_KEY_SCRATCHPAD","CONFIG_KEY_SEND","RESUME","CONFIG_KEY_CHECKPOINT_NS","XXH3","GraphInterrupt"],"sources":["../src/interrupt.ts"],"sourcesContent":["import { AsyncLocalStorageProviderSingleton } from \"@langchain/core/singletons\";\nimport { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n type JSONSchema,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n type InteropZodType,\n interopParse,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n BaseCheckpointSaver,\n type PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { GraphInterrupt, GraphValueError } from \"./errors.js\";\nimport {\n CONFIG_KEY_CHECKPOINT_NS,\n CONFIG_KEY_SCRATCHPAD,\n CONFIG_KEY_SEND,\n CONFIG_KEY_CHECKPOINTER,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n RESUME,\n type Interrupt,\n} from \"./constants.js\";\nimport { PregelScratchpad } from \"./pregel/types.js\";\nimport { XXH3 } from \"./hash.js\";\n\nexport interface InterruptOptions {\n /**\n * Schema for the value expected when the graph is resumed, surfaced to\n * clients on `Interrupt.response_schema` (as JSON Schema) so they can render\n * a typed input form. A Zod schema also parses the resume value, and the\n * parsed value is what `interrupt` returns; a JSON Schema object is passed\n * through to clients without validating the resume value.\n */\n responseSchema?: InteropZodType | JSONSchema;\n}\n\n/**\n * Interrupts the execution of a graph node.\n * This function can be used to pause execution of a node, and return the value of the `resume`\n * input when the graph is re-invoked using `Command`.\n * Multiple interrupts can be called within a single node, and each will be handled sequentially.\n *\n * When an interrupt is called:\n * 1. If there's a `resume` value available (from a previous `Command`), it returns that value.\n * 2. Otherwise, it throws a `GraphInterrupt` with the provided value\n * 3. The graph can be resumed by passing a `Command` with a `resume` value\n *\n * Because the `interrupt` function propagates by throwing a special `GraphInterrupt` error,\n * you should avoid using `try/catch` blocks around the `interrupt` function,\n * or if you do, ensure that the `GraphInterrupt` error is thrown again within your `catch` block.\n *\n * @param value - The value to include in the interrupt. This will be available in task.interrupts[].value\n * @param options - Optional settings. `responseSchema` describes the expected resume value and is\n * available in task.interrupts[].response_schema as JSON Schema; a Zod schema also validates the resume value.\n * @returns The `resume` value provided when the graph is re-invoked with a Command, parsed by\n * `responseSchema` when it is a Zod schema\n *\n * @example\n * ```typescript\n * // Define a node that uses multiple interrupts\n * const nodeWithInterrupts = () => {\n * // First interrupt - will pause execution and include {value: 1} in task values\n * const answer1 = interrupt({ value: 1 });\n *\n * // Second interrupt - only called after first interrupt is resumed\n * const answer2 = interrupt({ value: 2 });\n *\n * // Use the resume values\n * return { myKey: answer1 + \" \" + answer2 };\n * };\n *\n * // Resume the graph after first interrupt\n * await graph.stream(new Command({ resume: \"answer 1\" }));\n *\n * // Resume the graph after second interrupt\n * await graph.stream(new Command({ resume: \"answer 2\" }));\n * // Final result: { myKey: \"answer 1 answer 2\" }\n * ```\n *\n * @throws {Error} If called outside the context of a graph\n * @throws {GraphInterrupt} When no resume value is available\n * @throws {ZodError} When the resume value does not match a Zod `responseSchema`\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function interrupt<I = unknown, R = any>(\n value: I,\n options?: InterruptOptions\n): R {\n const config: RunnableConfig | undefined =\n AsyncLocalStorageProviderSingleton.getRunnableConfig();\n if (!config) {\n throw new Error(\"Called interrupt() outside the context of a graph.\");\n }\n\n const conf = config.configurable;\n if (!conf) {\n throw new Error(\"No configurable found in config\");\n }\n\n const checkpointer: BaseCheckpointSaver = conf[CONFIG_KEY_CHECKPOINTER];\n if (!checkpointer) {\n throw new GraphValueError(\"No checkpointer set\", {\n lc_error_code: \"MISSING_CHECKPOINTER\",\n });\n }\n\n const schema = options?.responseSchema;\n const parseResume = (resume: unknown): R =>\n (schema !== undefined && isInteropZodSchema(schema)\n ? interopParse(schema, resume)\n : resume) as R;\n\n // Track interrupt index\n const scratchpad: PregelScratchpad = conf[CONFIG_KEY_SCRATCHPAD];\n scratchpad.interruptCounter += 1;\n const idx = scratchpad.interruptCounter;\n\n // Find previous resume values\n if (scratchpad.resume.length > 0 && idx < scratchpad.resume.length) {\n const parsed = parseResume(scratchpad.resume[idx]);\n // Persist only through the interrupt being consumed. Values past `idx` belong\n // to later interrupts and may be unvalidated mapped resumes; a failing one must\n // not become durable, or its retry can never replace it.\n conf[CONFIG_KEY_SEND]?.([\n [RESUME, scratchpad.resume.slice(0, idx + 1)] as PendingWrite,\n ]);\n return parsed;\n }\n\n // Find current resume value\n if (scratchpad.nullResume !== undefined) {\n if (scratchpad.resume.length !== idx) {\n throw new Error(\n `Resume length mismatch: ${scratchpad.resume.length} !== ${idx}`\n );\n }\n const v = scratchpad.consumeNullResume();\n const parsed = parseResume(v);\n scratchpad.resume.push(v);\n conf[CONFIG_KEY_SEND]?.([[RESUME, scratchpad.resume] as PendingWrite]);\n return parsed;\n }\n\n // No resume value found\n const ns: string[] | undefined = conf[CONFIG_KEY_CHECKPOINT_NS]?.split(\n CHECKPOINT_NAMESPACE_SEPARATOR\n );\n\n const id = ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : undefined;\n const pending: Interrupt<I> = { id, value };\n if (schema !== undefined) {\n pending.response_schema = toJsonSchema(schema);\n }\n throw new GraphInterrupt([pending]);\n}\n\ntype FilterAny<X> =\n (<T>() => T extends X ? 1 : 2) extends <\n T,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n >() => T extends any ? 1 : 2\n ? never\n : X;\n\nexport type InferInterruptInputType<T> = T extends typeof interrupt<\n infer I,\n unknown\n>\n ? I\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptInputType<T[K]> }[keyof T]\n : unknown;\n\nexport type InferInterruptResumeType<\n T,\n TInner = false,\n> = T extends typeof interrupt<never, infer R>\n ? TInner extends true\n ? FilterAny<R>\n : R\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptResumeType<T[K], true> }[keyof T]\n : unknown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFA,SAAgB,UACd,OACA,SACG;CACH,MAAM,SACJA,2BAAAA,mCAAmC,mBAAmB;AACxD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,qDAAqD;CAGvE,MAAM,OAAO,OAAO;AACpB,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,kCAAkC;AAIpD,KAAI,CADsC,KAAA,yBAExC,OAAM,IAAIC,eAAAA,gBAAgB,uBAAuB,EAC/C,eAAe,wBAChB,CAAC;CAGJ,MAAM,SAAS,SAAS;CACxB,MAAM,eAAe,WAClB,WAAW,KAAA,MAAA,GAAA,4BAAA,oBAAgC,OAAO,IAAA,GAAA,4BAAA,cAClC,QAAQ,OAAO,GAC5B;CAGN,MAAM,aAA+B,KAAKC,kBAAAA;AAC1C,YAAW,oBAAoB;CAC/B,MAAM,MAAM,WAAW;AAGvB,KAAI,WAAW,OAAO,SAAS,KAAK,MAAM,WAAW,OAAO,QAAQ;EAClE,MAAM,SAAS,YAAY,WAAW,OAAO,KAAK;AAIlD,OAAKC,kBAAAA,mBAAmB,CACtB,CAACC,kBAAAA,QAAQ,WAAW,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC,CAC9C,CAAC;AACF,SAAO;;AAIT,KAAI,WAAW,eAAe,KAAA,GAAW;AACvC,MAAI,WAAW,OAAO,WAAW,IAC/B,OAAM,IAAI,MACR,2BAA2B,WAAW,OAAO,OAAO,OAAO,MAC5D;EAEH,MAAM,IAAI,WAAW,mBAAmB;EACxC,MAAM,SAAS,YAAY,EAAE;AAC7B,aAAW,OAAO,KAAK,EAAE;AACzB,OAAKD,kBAAAA,mBAAmB,CAAC,CAACC,kBAAAA,QAAQ,WAAW,OAAO,CAAiB,CAAC;AACtE,SAAO;;CAIT,MAAM,KAA2B,KAAKC,kBAAAA,2BAA2B,MAAA,IAEhE;CAGD,MAAM,UAAwB;EAAE,IADrB,KAAKC,aAAAA,KAAK,GAAG,KAAA,IAAoC,CAAC,GAAG,KAAA;EAC5B;EAAO;AAC3C,KAAI,WAAW,KAAA,EACb,SAAQ,mBAAA,GAAA,kCAAA,cAA+B,OAAO;AAEhD,OAAM,IAAIC,eAAAA,eAAe,CAAC,QAAQ,CAAC"}
1
+ {"version":3,"file":"interrupt.cjs","names":["AsyncLocalStorageProviderSingleton","GraphValueError","CONFIG_KEY_SCRATCHPAD","CONFIG_KEY_SEND","RESUME","CONFIG_KEY_CHECKPOINT_NS","XXH3","GraphInterrupt"],"sources":["../src/interrupt.ts"],"sourcesContent":["import { AsyncLocalStorageProviderSingleton } from \"@langchain/core/singletons\";\nimport { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n type JSONSchema,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n type InteropZodType,\n interopParse,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n BaseCheckpointSaver,\n type PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport {\n GraphInterrupt,\n GraphValueError,\n _markInvalidResume,\n} from \"./errors.js\";\nimport {\n CONFIG_KEY_CHECKPOINT_NS,\n CONFIG_KEY_SCRATCHPAD,\n CONFIG_KEY_SEND,\n CONFIG_KEY_CHECKPOINTER,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n RESUME,\n type Interrupt,\n} from \"./constants.js\";\nimport { PregelScratchpad } from \"./pregel/types.js\";\nimport { XXH3 } from \"./hash.js\";\n\nexport interface InterruptOptions {\n /**\n * Schema for the value expected when the graph is resumed, surfaced to\n * clients on `Interrupt.response_schema` (as JSON Schema) so they can render\n * a typed input form. A Zod schema also parses the resume value, and the\n * parsed value is what `interrupt` returns; a JSON Schema object is passed\n * through to clients without validating the resume value.\n */\n responseSchema?: InteropZodType | JSONSchema;\n}\n\n/**\n * Interrupts the execution of a graph node.\n * This function can be used to pause execution of a node, and return the value of the `resume`\n * input when the graph is re-invoked using `Command`.\n * Multiple interrupts can be called within a single node, and each will be handled sequentially.\n *\n * When an interrupt is called:\n * 1. If there's a `resume` value available (from a previous `Command`), it returns that value.\n * 2. Otherwise, it throws a `GraphInterrupt` with the provided value\n * 3. The graph can be resumed by passing a `Command` with a `resume` value\n *\n * Because the `interrupt` function propagates by throwing a special `GraphInterrupt` error,\n * you should avoid using `try/catch` blocks around the `interrupt` function,\n * or if you do, ensure that the `GraphInterrupt` error is thrown again within your `catch` block.\n *\n * @param value - The value to include in the interrupt. This will be available in task.interrupts[].value\n * @param options - Optional settings. `responseSchema` describes the expected resume value and is\n * available in task.interrupts[].response_schema as JSON Schema; a Zod schema also validates the resume value.\n * @returns The `resume` value provided when the graph is re-invoked with a Command, parsed by\n * `responseSchema` when it is a Zod schema\n *\n * @example\n * ```typescript\n * // Define a node that uses multiple interrupts\n * const nodeWithInterrupts = () => {\n * // First interrupt - will pause execution and include {value: 1} in task values\n * const answer1 = interrupt({ value: 1 });\n *\n * // Second interrupt - only called after first interrupt is resumed\n * const answer2 = interrupt({ value: 2 });\n *\n * // Use the resume values\n * return { myKey: answer1 + \" \" + answer2 };\n * };\n *\n * // Resume the graph after first interrupt\n * await graph.stream(new Command({ resume: \"answer 1\" }));\n *\n * // Resume the graph after second interrupt\n * await graph.stream(new Command({ resume: \"answer 2\" }));\n * // Final result: { myKey: \"answer 1 answer 2\" }\n * ```\n *\n * @throws {Error} If called outside the context of a graph\n * @throws {GraphInterrupt} When no resume value is available\n * @throws {ZodError} When the resume value does not match a Zod `responseSchema`\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function interrupt<I = unknown, R = any>(\n value: I,\n options?: InterruptOptions\n): R {\n const config: RunnableConfig | undefined =\n AsyncLocalStorageProviderSingleton.getRunnableConfig();\n if (!config) {\n throw new Error(\"Called interrupt() outside the context of a graph.\");\n }\n\n const conf = config.configurable;\n if (!conf) {\n throw new Error(\"No configurable found in config\");\n }\n\n const checkpointer: BaseCheckpointSaver = conf[CONFIG_KEY_CHECKPOINTER];\n if (!checkpointer) {\n throw new GraphValueError(\"No checkpointer set\", {\n lc_error_code: \"MISSING_CHECKPOINTER\",\n });\n }\n\n const schema = options?.responseSchema;\n const parseResume = (resume: unknown): R => {\n if (schema === undefined || !isInteropZodSchema(schema)) return resume as R;\n try {\n return interopParse(schema, resume) as R;\n } catch (error) {\n _markInvalidResume(error);\n throw error;\n }\n };\n\n // Track interrupt index\n const scratchpad: PregelScratchpad = conf[CONFIG_KEY_SCRATCHPAD];\n scratchpad.interruptCounter += 1;\n const idx = scratchpad.interruptCounter;\n\n // Find previous resume values\n if (scratchpad.resume.length > 0 && idx < scratchpad.resume.length) {\n const parsed = parseResume(scratchpad.resume[idx]);\n // Persist only through the interrupt being consumed. Values past `idx` belong\n // to later interrupts and may be unvalidated mapped resumes; a failing one must\n // not become durable, or its retry can never replace it.\n conf[CONFIG_KEY_SEND]?.([\n [RESUME, scratchpad.resume.slice(0, idx + 1)] as PendingWrite,\n ]);\n return parsed;\n }\n\n // Find current resume value\n if (scratchpad.nullResume !== undefined) {\n if (scratchpad.resume.length !== idx) {\n throw new Error(\n `Resume length mismatch: ${scratchpad.resume.length} !== ${idx}`\n );\n }\n const v = scratchpad.consumeNullResume();\n const parsed = parseResume(v);\n scratchpad.resume.push(v);\n conf[CONFIG_KEY_SEND]?.([[RESUME, scratchpad.resume] as PendingWrite]);\n return parsed;\n }\n\n // No resume value found\n const ns: string[] | undefined = conf[CONFIG_KEY_CHECKPOINT_NS]?.split(\n CHECKPOINT_NAMESPACE_SEPARATOR\n );\n\n const id = ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : undefined;\n const pending: Interrupt<I> = { id, value };\n if (schema !== undefined) {\n pending.response_schema = toJsonSchema(schema);\n }\n throw new GraphInterrupt([pending]);\n}\n\ntype FilterAny<X> =\n (<T>() => T extends X ? 1 : 2) extends <\n T,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n >() => T extends any ? 1 : 2\n ? never\n : X;\n\nexport type InferInterruptInputType<T> = T extends typeof interrupt<\n infer I,\n unknown\n>\n ? I\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptInputType<T[K]> }[keyof T]\n : unknown;\n\nexport type InferInterruptResumeType<\n T,\n TInner = false,\n> = T extends typeof interrupt<never, infer R>\n ? TInner extends true\n ? FilterAny<R>\n : R\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptResumeType<T[K], true> }[keyof T]\n : unknown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,SAAgB,UACd,OACA,SACG;CACH,MAAM,SACJA,2BAAAA,mCAAmC,mBAAmB;AACxD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,qDAAqD;CAGvE,MAAM,OAAO,OAAO;AACpB,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,kCAAkC;AAIpD,KAAI,CADsC,KAAA,yBAExC,OAAM,IAAIC,eAAAA,gBAAgB,uBAAuB,EAC/C,eAAe,wBAChB,CAAC;CAGJ,MAAM,SAAS,SAAS;CACxB,MAAM,eAAe,WAAuB;AAC1C,MAAI,WAAW,KAAA,KAAa,EAAA,GAAA,4BAAA,oBAAoB,OAAO,CAAE,QAAO;AAChE,MAAI;AACF,WAAA,GAAA,4BAAA,cAAoB,QAAQ,OAAO;WAC5B,OAAO;AACd,kBAAA,mBAAmB,MAAM;AACzB,SAAM;;;CAKV,MAAM,aAA+B,KAAKC,kBAAAA;AAC1C,YAAW,oBAAoB;CAC/B,MAAM,MAAM,WAAW;AAGvB,KAAI,WAAW,OAAO,SAAS,KAAK,MAAM,WAAW,OAAO,QAAQ;EAClE,MAAM,SAAS,YAAY,WAAW,OAAO,KAAK;AAIlD,OAAKC,kBAAAA,mBAAmB,CACtB,CAACC,kBAAAA,QAAQ,WAAW,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC,CAC9C,CAAC;AACF,SAAO;;AAIT,KAAI,WAAW,eAAe,KAAA,GAAW;AACvC,MAAI,WAAW,OAAO,WAAW,IAC/B,OAAM,IAAI,MACR,2BAA2B,WAAW,OAAO,OAAO,OAAO,MAC5D;EAEH,MAAM,IAAI,WAAW,mBAAmB;EACxC,MAAM,SAAS,YAAY,EAAE;AAC7B,aAAW,OAAO,KAAK,EAAE;AACzB,OAAKD,kBAAAA,mBAAmB,CAAC,CAACC,kBAAAA,QAAQ,WAAW,OAAO,CAAiB,CAAC;AACtE,SAAO;;CAIT,MAAM,KAA2B,KAAKC,kBAAAA,2BAA2B,MAAA,IAEhE;CAGD,MAAM,UAAwB;EAAE,IADrB,KAAKC,aAAAA,KAAK,GAAG,KAAA,IAAoC,CAAC,GAAG,KAAA;EAC5B;EAAO;AAC3C,KAAI,WAAW,KAAA,EACb,SAAQ,mBAAA,GAAA,kCAAA,cAA+B,OAAO;AAEhD,OAAM,IAAIC,eAAAA,eAAe,CAAC,QAAQ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"interrupt.d.cts","names":[],"sources":["../src/interrupt.ts"],"mappings":";;;;UA4BiB,gBAAA;;AAAjB;;;;;;EAQE,cAAA,GAAiB,cAAA,GAAiB,UAAA;AAAA;;AAmDpC;;;;;;;;;;;;;;;;;AAsEC;;;;;;;;;;;;;;;;;;AAUD;;;;;;;;;;;iBAhFgB,SAAA,sBAAA,CACd,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,gBAAA,GACT,CAAA;AAAA,KAqEE,SAAA,gBACO,CAAA,SAAU,CAAA,6BAGb,CAAA,iCAEH,CAAA;AAAA,KAEM,uBAAA,MAA6B,CAAA,gBAAiB,SAAA,qBAItD,CAAA,GAEA,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,uBAAA,CAAwB,CAAA,CAAE,CAAA,WAAY,CAAA;AAAA,KAGlD,wBAAA,sBAGR,CAAA,gBAAiB,SAAA,mBACjB,MAAA,gBACE,SAAA,CAAU,CAAA,IACV,CAAA,GAEF,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,wBAAA,CAAyB,CAAA,CAAE,CAAA,iBAAkB,CAAA"}
1
+ {"version":3,"file":"interrupt.d.cts","names":[],"sources":["../src/interrupt.ts"],"mappings":";;;;UAgCiB,gBAAA;;AAAjB;;;;;;EAQE,cAAA,GAAiB,cAAA,GAAiB,UAAA;AAAA;;AAmDpC;;;;;;;;;;;;;;;;;AA2EC;;;;;;;;;;;;;;;;;;AAUD;;;;;;;;;;;iBArFgB,SAAA,sBAAA,CACd,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,gBAAA,GACT,CAAA;AAAA,KA0EE,SAAA,gBACO,CAAA,SAAU,CAAA,6BAGb,CAAA,iCAEH,CAAA;AAAA,KAEM,uBAAA,MAA6B,CAAA,gBAAiB,SAAA,qBAItD,CAAA,GAEA,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,uBAAA,CAAwB,CAAA,CAAE,CAAA,WAAY,CAAA;AAAA,KAGlD,wBAAA,sBAGR,CAAA,gBAAiB,SAAA,mBACjB,MAAA,gBACE,SAAA,CAAU,CAAA,IACV,CAAA,GAEF,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,wBAAA,CAAyB,CAAA,CAAE,CAAA,iBAAkB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"interrupt.d.ts","names":[],"sources":["../src/interrupt.ts"],"mappings":";;;;UA4BiB,gBAAA;;AAAjB;;;;;;EAQE,cAAA,GAAiB,cAAA,GAAiB,UAAA;AAAA;;AAmDpC;;;;;;;;;;;;;;;;;AAsEC;;;;;;;;;;;;;;;;;;AAUD;;;;;;;;;;;iBAhFgB,SAAA,sBAAA,CACd,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,gBAAA,GACT,CAAA;AAAA,KAqEE,SAAA,gBACO,CAAA,SAAU,CAAA,6BAGb,CAAA,iCAEH,CAAA;AAAA,KAEM,uBAAA,MAA6B,CAAA,gBAAiB,SAAA,qBAItD,CAAA,GAEA,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,uBAAA,CAAwB,CAAA,CAAE,CAAA,WAAY,CAAA;AAAA,KAGlD,wBAAA,sBAGR,CAAA,gBAAiB,SAAA,mBACjB,MAAA,gBACE,SAAA,CAAU,CAAA,IACV,CAAA,GAEF,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,wBAAA,CAAyB,CAAA,CAAE,CAAA,iBAAkB,CAAA"}
1
+ {"version":3,"file":"interrupt.d.ts","names":[],"sources":["../src/interrupt.ts"],"mappings":";;;;UAgCiB,gBAAA;;AAAjB;;;;;;EAQE,cAAA,GAAiB,cAAA,GAAiB,UAAA;AAAA;;AAmDpC;;;;;;;;;;;;;;;;;AA2EC;;;;;;;;;;;;;;;;;;AAUD;;;;;;;;;;;iBArFgB,SAAA,sBAAA,CACd,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,gBAAA,GACT,CAAA;AAAA,KA0EE,SAAA,gBACO,CAAA,SAAU,CAAA,6BAGb,CAAA,iCAEH,CAAA;AAAA,KAEM,uBAAA,MAA6B,CAAA,gBAAiB,SAAA,qBAItD,CAAA,GAEA,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,uBAAA,CAAwB,CAAA,CAAE,CAAA,WAAY,CAAA;AAAA,KAGlD,wBAAA,sBAGR,CAAA,gBAAiB,SAAA,mBACjB,MAAA,gBACE,SAAA,CAAU,CAAA,IACV,CAAA,GAEF,CAAA;EAAA,CAAa,GAAA,kBAAqB,SAAA;AAAA,kBAClB,CAAA,GAAI,wBAAA,CAAyB,CAAA,CAAE,CAAA,iBAAkB,CAAA"}
package/dist/interrupt.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CONFIG_KEY_CHECKPOINT_NS, CONFIG_KEY_SCRATCHPAD, CONFIG_KEY_SEND, RESUME } from "./constants.js";
2
- import { GraphInterrupt, GraphValueError } from "./errors.js";
2
+ import { GraphInterrupt, GraphValueError, _markInvalidResume } from "./errors.js";
3
3
  import { XXH3 } from "./hash.js";
4
4
  import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
5
5
  import { toJsonSchema } from "@langchain/core/utils/json_schema";
@@ -59,7 +59,15 @@ function interrupt(value, options) {
59
59
  if (!conf) throw new Error("No configurable found in config");
60
60
  if (!conf["__pregel_checkpointer"]) throw new GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" });
61
61
  const schema = options?.responseSchema;
62
- const parseResume = (resume) => schema !== void 0 && isInteropZodSchema(schema) ? interopParse(schema, resume) : resume;
62
+ const parseResume = (resume) => {
63
+ if (schema === void 0 || !isInteropZodSchema(schema)) return resume;
64
+ try {
65
+ return interopParse(schema, resume);
66
+ } catch (error) {
67
+ _markInvalidResume(error);
68
+ throw error;
69
+ }
70
+ };
63
71
  const scratchpad = conf[CONFIG_KEY_SCRATCHPAD];
64
72
  scratchpad.interruptCounter += 1;
65
73
  const idx = scratchpad.interruptCounter;
@@ -1 +1 @@
1
- {"version":3,"file":"interrupt.js","names":[],"sources":["../src/interrupt.ts"],"sourcesContent":["import { AsyncLocalStorageProviderSingleton } from \"@langchain/core/singletons\";\nimport { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n type JSONSchema,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n type InteropZodType,\n interopParse,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n BaseCheckpointSaver,\n type PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { GraphInterrupt, GraphValueError } from \"./errors.js\";\nimport {\n CONFIG_KEY_CHECKPOINT_NS,\n CONFIG_KEY_SCRATCHPAD,\n CONFIG_KEY_SEND,\n CONFIG_KEY_CHECKPOINTER,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n RESUME,\n type Interrupt,\n} from \"./constants.js\";\nimport { PregelScratchpad } from \"./pregel/types.js\";\nimport { XXH3 } from \"./hash.js\";\n\nexport interface InterruptOptions {\n /**\n * Schema for the value expected when the graph is resumed, surfaced to\n * clients on `Interrupt.response_schema` (as JSON Schema) so they can render\n * a typed input form. A Zod schema also parses the resume value, and the\n * parsed value is what `interrupt` returns; a JSON Schema object is passed\n * through to clients without validating the resume value.\n */\n responseSchema?: InteropZodType | JSONSchema;\n}\n\n/**\n * Interrupts the execution of a graph node.\n * This function can be used to pause execution of a node, and return the value of the `resume`\n * input when the graph is re-invoked using `Command`.\n * Multiple interrupts can be called within a single node, and each will be handled sequentially.\n *\n * When an interrupt is called:\n * 1. If there's a `resume` value available (from a previous `Command`), it returns that value.\n * 2. Otherwise, it throws a `GraphInterrupt` with the provided value\n * 3. The graph can be resumed by passing a `Command` with a `resume` value\n *\n * Because the `interrupt` function propagates by throwing a special `GraphInterrupt` error,\n * you should avoid using `try/catch` blocks around the `interrupt` function,\n * or if you do, ensure that the `GraphInterrupt` error is thrown again within your `catch` block.\n *\n * @param value - The value to include in the interrupt. This will be available in task.interrupts[].value\n * @param options - Optional settings. `responseSchema` describes the expected resume value and is\n * available in task.interrupts[].response_schema as JSON Schema; a Zod schema also validates the resume value.\n * @returns The `resume` value provided when the graph is re-invoked with a Command, parsed by\n * `responseSchema` when it is a Zod schema\n *\n * @example\n * ```typescript\n * // Define a node that uses multiple interrupts\n * const nodeWithInterrupts = () => {\n * // First interrupt - will pause execution and include {value: 1} in task values\n * const answer1 = interrupt({ value: 1 });\n *\n * // Second interrupt - only called after first interrupt is resumed\n * const answer2 = interrupt({ value: 2 });\n *\n * // Use the resume values\n * return { myKey: answer1 + \" \" + answer2 };\n * };\n *\n * // Resume the graph after first interrupt\n * await graph.stream(new Command({ resume: \"answer 1\" }));\n *\n * // Resume the graph after second interrupt\n * await graph.stream(new Command({ resume: \"answer 2\" }));\n * // Final result: { myKey: \"answer 1 answer 2\" }\n * ```\n *\n * @throws {Error} If called outside the context of a graph\n * @throws {GraphInterrupt} When no resume value is available\n * @throws {ZodError} When the resume value does not match a Zod `responseSchema`\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function interrupt<I = unknown, R = any>(\n value: I,\n options?: InterruptOptions\n): R {\n const config: RunnableConfig | undefined =\n AsyncLocalStorageProviderSingleton.getRunnableConfig();\n if (!config) {\n throw new Error(\"Called interrupt() outside the context of a graph.\");\n }\n\n const conf = config.configurable;\n if (!conf) {\n throw new Error(\"No configurable found in config\");\n }\n\n const checkpointer: BaseCheckpointSaver = conf[CONFIG_KEY_CHECKPOINTER];\n if (!checkpointer) {\n throw new GraphValueError(\"No checkpointer set\", {\n lc_error_code: \"MISSING_CHECKPOINTER\",\n });\n }\n\n const schema = options?.responseSchema;\n const parseResume = (resume: unknown): R =>\n (schema !== undefined && isInteropZodSchema(schema)\n ? interopParse(schema, resume)\n : resume) as R;\n\n // Track interrupt index\n const scratchpad: PregelScratchpad = conf[CONFIG_KEY_SCRATCHPAD];\n scratchpad.interruptCounter += 1;\n const idx = scratchpad.interruptCounter;\n\n // Find previous resume values\n if (scratchpad.resume.length > 0 && idx < scratchpad.resume.length) {\n const parsed = parseResume(scratchpad.resume[idx]);\n // Persist only through the interrupt being consumed. Values past `idx` belong\n // to later interrupts and may be unvalidated mapped resumes; a failing one must\n // not become durable, or its retry can never replace it.\n conf[CONFIG_KEY_SEND]?.([\n [RESUME, scratchpad.resume.slice(0, idx + 1)] as PendingWrite,\n ]);\n return parsed;\n }\n\n // Find current resume value\n if (scratchpad.nullResume !== undefined) {\n if (scratchpad.resume.length !== idx) {\n throw new Error(\n `Resume length mismatch: ${scratchpad.resume.length} !== ${idx}`\n );\n }\n const v = scratchpad.consumeNullResume();\n const parsed = parseResume(v);\n scratchpad.resume.push(v);\n conf[CONFIG_KEY_SEND]?.([[RESUME, scratchpad.resume] as PendingWrite]);\n return parsed;\n }\n\n // No resume value found\n const ns: string[] | undefined = conf[CONFIG_KEY_CHECKPOINT_NS]?.split(\n CHECKPOINT_NAMESPACE_SEPARATOR\n );\n\n const id = ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : undefined;\n const pending: Interrupt<I> = { id, value };\n if (schema !== undefined) {\n pending.response_schema = toJsonSchema(schema);\n }\n throw new GraphInterrupt([pending]);\n}\n\ntype FilterAny<X> =\n (<T>() => T extends X ? 1 : 2) extends <\n T,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n >() => T extends any ? 1 : 2\n ? never\n : X;\n\nexport type InferInterruptInputType<T> = T extends typeof interrupt<\n infer I,\n unknown\n>\n ? I\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptInputType<T[K]> }[keyof T]\n : unknown;\n\nexport type InferInterruptResumeType<\n T,\n TInner = false,\n> = T extends typeof interrupt<never, infer R>\n ? TInner extends true\n ? FilterAny<R>\n : R\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptResumeType<T[K], true> }[keyof T]\n : unknown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFA,SAAgB,UACd,OACA,SACG;CACH,MAAM,SACJ,mCAAmC,mBAAmB;AACxD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,qDAAqD;CAGvE,MAAM,OAAO,OAAO;AACpB,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,kCAAkC;AAIpD,KAAI,CADsC,KAAA,yBAExC,OAAM,IAAI,gBAAgB,uBAAuB,EAC/C,eAAe,wBAChB,CAAC;CAGJ,MAAM,SAAS,SAAS;CACxB,MAAM,eAAe,WAClB,WAAW,KAAA,KAAa,mBAAmB,OAAO,GAC/C,aAAa,QAAQ,OAAO,GAC5B;CAGN,MAAM,aAA+B,KAAK;AAC1C,YAAW,oBAAoB;CAC/B,MAAM,MAAM,WAAW;AAGvB,KAAI,WAAW,OAAO,SAAS,KAAK,MAAM,WAAW,OAAO,QAAQ;EAClE,MAAM,SAAS,YAAY,WAAW,OAAO,KAAK;AAIlD,OAAK,mBAAmB,CACtB,CAAC,QAAQ,WAAW,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC,CAC9C,CAAC;AACF,SAAO;;AAIT,KAAI,WAAW,eAAe,KAAA,GAAW;AACvC,MAAI,WAAW,OAAO,WAAW,IAC/B,OAAM,IAAI,MACR,2BAA2B,WAAW,OAAO,OAAO,OAAO,MAC5D;EAEH,MAAM,IAAI,WAAW,mBAAmB;EACxC,MAAM,SAAS,YAAY,EAAE;AAC7B,aAAW,OAAO,KAAK,EAAE;AACzB,OAAK,mBAAmB,CAAC,CAAC,QAAQ,WAAW,OAAO,CAAiB,CAAC;AACtE,SAAO;;CAIT,MAAM,KAA2B,KAAK,2BAA2B,MAAA,IAEhE;CAGD,MAAM,UAAwB;EAAE,IADrB,KAAK,KAAK,GAAG,KAAA,IAAoC,CAAC,GAAG,KAAA;EAC5B;EAAO;AAC3C,KAAI,WAAW,KAAA,EACb,SAAQ,kBAAkB,aAAa,OAAO;AAEhD,OAAM,IAAI,eAAe,CAAC,QAAQ,CAAC"}
1
+ {"version":3,"file":"interrupt.js","names":[],"sources":["../src/interrupt.ts"],"sourcesContent":["import { AsyncLocalStorageProviderSingleton } from \"@langchain/core/singletons\";\nimport { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n type JSONSchema,\n toJsonSchema,\n} from \"@langchain/core/utils/json_schema\";\nimport {\n type InteropZodType,\n interopParse,\n isInteropZodSchema,\n} from \"@langchain/core/utils/types\";\nimport {\n BaseCheckpointSaver,\n type PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport {\n GraphInterrupt,\n GraphValueError,\n _markInvalidResume,\n} from \"./errors.js\";\nimport {\n CONFIG_KEY_CHECKPOINT_NS,\n CONFIG_KEY_SCRATCHPAD,\n CONFIG_KEY_SEND,\n CONFIG_KEY_CHECKPOINTER,\n CHECKPOINT_NAMESPACE_SEPARATOR,\n RESUME,\n type Interrupt,\n} from \"./constants.js\";\nimport { PregelScratchpad } from \"./pregel/types.js\";\nimport { XXH3 } from \"./hash.js\";\n\nexport interface InterruptOptions {\n /**\n * Schema for the value expected when the graph is resumed, surfaced to\n * clients on `Interrupt.response_schema` (as JSON Schema) so they can render\n * a typed input form. A Zod schema also parses the resume value, and the\n * parsed value is what `interrupt` returns; a JSON Schema object is passed\n * through to clients without validating the resume value.\n */\n responseSchema?: InteropZodType | JSONSchema;\n}\n\n/**\n * Interrupts the execution of a graph node.\n * This function can be used to pause execution of a node, and return the value of the `resume`\n * input when the graph is re-invoked using `Command`.\n * Multiple interrupts can be called within a single node, and each will be handled sequentially.\n *\n * When an interrupt is called:\n * 1. If there's a `resume` value available (from a previous `Command`), it returns that value.\n * 2. Otherwise, it throws a `GraphInterrupt` with the provided value\n * 3. The graph can be resumed by passing a `Command` with a `resume` value\n *\n * Because the `interrupt` function propagates by throwing a special `GraphInterrupt` error,\n * you should avoid using `try/catch` blocks around the `interrupt` function,\n * or if you do, ensure that the `GraphInterrupt` error is thrown again within your `catch` block.\n *\n * @param value - The value to include in the interrupt. This will be available in task.interrupts[].value\n * @param options - Optional settings. `responseSchema` describes the expected resume value and is\n * available in task.interrupts[].response_schema as JSON Schema; a Zod schema also validates the resume value.\n * @returns The `resume` value provided when the graph is re-invoked with a Command, parsed by\n * `responseSchema` when it is a Zod schema\n *\n * @example\n * ```typescript\n * // Define a node that uses multiple interrupts\n * const nodeWithInterrupts = () => {\n * // First interrupt - will pause execution and include {value: 1} in task values\n * const answer1 = interrupt({ value: 1 });\n *\n * // Second interrupt - only called after first interrupt is resumed\n * const answer2 = interrupt({ value: 2 });\n *\n * // Use the resume values\n * return { myKey: answer1 + \" \" + answer2 };\n * };\n *\n * // Resume the graph after first interrupt\n * await graph.stream(new Command({ resume: \"answer 1\" }));\n *\n * // Resume the graph after second interrupt\n * await graph.stream(new Command({ resume: \"answer 2\" }));\n * // Final result: { myKey: \"answer 1 answer 2\" }\n * ```\n *\n * @throws {Error} If called outside the context of a graph\n * @throws {GraphInterrupt} When no resume value is available\n * @throws {ZodError} When the resume value does not match a Zod `responseSchema`\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function interrupt<I = unknown, R = any>(\n value: I,\n options?: InterruptOptions\n): R {\n const config: RunnableConfig | undefined =\n AsyncLocalStorageProviderSingleton.getRunnableConfig();\n if (!config) {\n throw new Error(\"Called interrupt() outside the context of a graph.\");\n }\n\n const conf = config.configurable;\n if (!conf) {\n throw new Error(\"No configurable found in config\");\n }\n\n const checkpointer: BaseCheckpointSaver = conf[CONFIG_KEY_CHECKPOINTER];\n if (!checkpointer) {\n throw new GraphValueError(\"No checkpointer set\", {\n lc_error_code: \"MISSING_CHECKPOINTER\",\n });\n }\n\n const schema = options?.responseSchema;\n const parseResume = (resume: unknown): R => {\n if (schema === undefined || !isInteropZodSchema(schema)) return resume as R;\n try {\n return interopParse(schema, resume) as R;\n } catch (error) {\n _markInvalidResume(error);\n throw error;\n }\n };\n\n // Track interrupt index\n const scratchpad: PregelScratchpad = conf[CONFIG_KEY_SCRATCHPAD];\n scratchpad.interruptCounter += 1;\n const idx = scratchpad.interruptCounter;\n\n // Find previous resume values\n if (scratchpad.resume.length > 0 && idx < scratchpad.resume.length) {\n const parsed = parseResume(scratchpad.resume[idx]);\n // Persist only through the interrupt being consumed. Values past `idx` belong\n // to later interrupts and may be unvalidated mapped resumes; a failing one must\n // not become durable, or its retry can never replace it.\n conf[CONFIG_KEY_SEND]?.([\n [RESUME, scratchpad.resume.slice(0, idx + 1)] as PendingWrite,\n ]);\n return parsed;\n }\n\n // Find current resume value\n if (scratchpad.nullResume !== undefined) {\n if (scratchpad.resume.length !== idx) {\n throw new Error(\n `Resume length mismatch: ${scratchpad.resume.length} !== ${idx}`\n );\n }\n const v = scratchpad.consumeNullResume();\n const parsed = parseResume(v);\n scratchpad.resume.push(v);\n conf[CONFIG_KEY_SEND]?.([[RESUME, scratchpad.resume] as PendingWrite]);\n return parsed;\n }\n\n // No resume value found\n const ns: string[] | undefined = conf[CONFIG_KEY_CHECKPOINT_NS]?.split(\n CHECKPOINT_NAMESPACE_SEPARATOR\n );\n\n const id = ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : undefined;\n const pending: Interrupt<I> = { id, value };\n if (schema !== undefined) {\n pending.response_schema = toJsonSchema(schema);\n }\n throw new GraphInterrupt([pending]);\n}\n\ntype FilterAny<X> =\n (<T>() => T extends X ? 1 : 2) extends <\n T,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n >() => T extends any ? 1 : 2\n ? never\n : X;\n\nexport type InferInterruptInputType<T> = T extends typeof interrupt<\n infer I,\n unknown\n>\n ? I\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptInputType<T[K]> }[keyof T]\n : unknown;\n\nexport type InferInterruptResumeType<\n T,\n TInner = false,\n> = T extends typeof interrupt<never, infer R>\n ? TInner extends true\n ? FilterAny<R>\n : R\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends { [key: string]: typeof interrupt<any, any> }\n ? { [K in keyof T]: InferInterruptResumeType<T[K], true> }[keyof T]\n : unknown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,SAAgB,UACd,OACA,SACG;CACH,MAAM,SACJ,mCAAmC,mBAAmB;AACxD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,qDAAqD;CAGvE,MAAM,OAAO,OAAO;AACpB,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,kCAAkC;AAIpD,KAAI,CADsC,KAAA,yBAExC,OAAM,IAAI,gBAAgB,uBAAuB,EAC/C,eAAe,wBAChB,CAAC;CAGJ,MAAM,SAAS,SAAS;CACxB,MAAM,eAAe,WAAuB;AAC1C,MAAI,WAAW,KAAA,KAAa,CAAC,mBAAmB,OAAO,CAAE,QAAO;AAChE,MAAI;AACF,UAAO,aAAa,QAAQ,OAAO;WAC5B,OAAO;AACd,sBAAmB,MAAM;AACzB,SAAM;;;CAKV,MAAM,aAA+B,KAAK;AAC1C,YAAW,oBAAoB;CAC/B,MAAM,MAAM,WAAW;AAGvB,KAAI,WAAW,OAAO,SAAS,KAAK,MAAM,WAAW,OAAO,QAAQ;EAClE,MAAM,SAAS,YAAY,WAAW,OAAO,KAAK;AAIlD,OAAK,mBAAmB,CACtB,CAAC,QAAQ,WAAW,OAAO,MAAM,GAAG,MAAM,EAAE,CAAC,CAC9C,CAAC;AACF,SAAO;;AAIT,KAAI,WAAW,eAAe,KAAA,GAAW;AACvC,MAAI,WAAW,OAAO,WAAW,IAC/B,OAAM,IAAI,MACR,2BAA2B,WAAW,OAAO,OAAO,OAAO,MAC5D;EAEH,MAAM,IAAI,WAAW,mBAAmB;EACxC,MAAM,SAAS,YAAY,EAAE;AAC7B,aAAW,OAAO,KAAK,EAAE;AACzB,OAAK,mBAAmB,CAAC,CAAC,QAAQ,WAAW,OAAO,CAAiB,CAAC;AACtE,SAAO;;CAIT,MAAM,KAA2B,KAAK,2BAA2B,MAAA,IAEhE;CAGD,MAAM,UAAwB;EAAE,IADrB,KAAK,KAAK,GAAG,KAAA,IAAoC,CAAC,GAAG,KAAA;EAC5B;EAAO;AAC3C,KAAI,WAAW,KAAA,EACb,SAAQ,kBAAkB,aAAa,OAAO;AAEhD,OAAM,IAAI,eAAe,CAAC,QAAQ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  const require_constants = require("../constants.cjs");
2
+ require("../errors.cjs");
2
3
  const require_config = require("./utils/config.cjs");
3
4
  const require_io = require("./io.cjs");
4
5
  const require_subgraph = require("./utils/subgraph.cjs");
@@ -1 +1 @@
1
- {"version":3,"file":"debug.cjs","names":["EXCLUDED_METADATA_KEYS","filterToUserTags","INTERRUPT","findSubgraphPregel","readChannels"],"sources":["../../src/pregel/debug.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n CheckpointMetadata,\n CheckpointPendingWrite,\n EXCLUDED_METADATA_KEYS,\n PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { BaseChannel } from \"../channels/base.js\";\nimport {\n ERROR,\n Interrupt,\n INTERRUPT,\n RETURN,\n TAG_HIDDEN,\n} from \"../constants.js\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n PregelExecutableTask,\n PregelTaskDescription,\n StateSnapshot,\n} from \"./types.js\";\nimport { readChannels } from \"./io.js\";\nimport { findSubgraphPregel } from \"./utils/subgraph.js\";\nimport { filterToUserTags } from \"./utils/config.js\";\n\ntype ConsoleColors = {\n start: string;\n end: string;\n};\n\ntype ConsoleColorMap = {\n [key: string]: ConsoleColors;\n};\n\nconst COLORS_MAP: ConsoleColorMap = {\n blue: {\n start: \"\\x1b[34m\",\n end: \"\\x1b[0m\",\n },\n green: {\n start: \"\\x1b[32m\",\n end: \"\\x1b[0m\",\n },\n yellow: {\n start: \"\\x1b[33;1m\",\n end: \"\\x1b[0m\",\n },\n};\n\n/**\n * Wrap some text in a color for printing to the console.\n */\nexport const wrap = (color: ConsoleColors, text: string): string =>\n `${color.start}${text}${color.end}`;\n\nexport function printCheckpoint<Value>(\n step: number,\n channels: Record<string, BaseChannel<Value>>\n) {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, \"[langgraph/checkpoint]\")}`,\n `Finishing step ${step}. Channel values:\\n`,\n `\\n${JSON.stringify(\n Object.fromEntries(_readChannels<Value>(channels)),\n null,\n 2\n )}`,\n ].join(\"\")\n );\n}\n\nexport function* _readChannels<Value>(\n channels: Record<string, BaseChannel<Value>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): IterableIterator<[string, any]> {\n for (const [name, channel] of Object.entries(channels)) {\n try {\n yield [name, channel.get()];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // Skip the channel if it's empty\n continue;\n } else {\n throw error; // Re-throw the error if it's not an EmptyChannelError\n }\n }\n }\n}\n\n/**\n * Build the user-meaningful metadata to forward on a task's stream payload.\n *\n * Drops langgraph's internal framework keys ({@link EXCLUDED_METADATA_KEYS}) —\n * which are redundant with the task's own fields and namespace — while keeping\n * keys like `lc_agent_name`, `ls_integration`, and any user-supplied metadata.\n * Filtered config tags are folded in under `tags`, mirroring the messages\n * stream handler. Returns `undefined` when there is nothing to forward.\n */\nfunction buildTaskMetadata(\n config: RunnableConfig | undefined\n): Record<string, unknown> | undefined {\n if (config == null) return undefined;\n const metadata: Record<string, unknown> = {};\n if (config.metadata != null) {\n for (const [key, value] of Object.entries(config.metadata)) {\n if (!EXCLUDED_METADATA_KEYS.has(key)) metadata[key] = value;\n }\n }\n const filteredTags = filterToUserTags(config.tags);\n if (filteredTags != null) metadata.tags = filteredTags;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nexport function* mapDebugTasks<N extends PropertyKey, C extends PropertyKey>(\n tasks: readonly PregelExecutableTask<N, C>[]\n) {\n for (const { id, name, input, config, triggers, writes } of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n\n const interrupts = writes\n .filter(([writeId, n]) => {\n return writeId === id && n === INTERRUPT;\n })\n .map(([, v]) => {\n return v;\n });\n const payload: {\n id: string;\n name: N;\n input: unknown;\n triggers: string[];\n interrupts: unknown[];\n metadata?: Record<string, unknown>;\n } = { id, name, input, triggers, interrupts };\n const metadata = buildTaskMetadata(config);\n if (metadata != null) payload.metadata = metadata;\n yield payload;\n }\n}\n\nfunction isMultipleChannelWrite(\n value: unknown\n): value is { $writes: unknown[] } {\n if (typeof value !== \"object\" || value === null) return false;\n return \"$writes\" in value && Array.isArray(value.$writes);\n}\n\nfunction mapTaskResultWrites(writes: PendingWrite<unknown>[]) {\n const result: Record<string, unknown> = {};\n\n for (const [channel, value] of writes) {\n const strChannel = String(channel);\n\n if (strChannel in result) {\n const channelWrites = isMultipleChannelWrite(result[strChannel])\n ? result[strChannel].$writes\n : [result[strChannel]];\n\n channelWrites.push(value);\n result[strChannel] = { $writes: channelWrites };\n } else {\n result[strChannel] = value;\n }\n }\n return result;\n}\n\nexport function* mapDebugTaskResults<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n tasks: readonly [PregelExecutableTask<N, C>, PendingWrite<C>[]][],\n streamChannels: PropertyKey | Array<PropertyKey>\n) {\n for (const [{ id, name, config }, writes] of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n yield {\n id,\n name,\n result: mapTaskResultWrites(\n writes.filter(([channel]) => {\n return Array.isArray(streamChannels)\n ? streamChannels.includes(channel)\n : channel === streamChannels;\n })\n ),\n interrupts: writes.filter((w) => w[0] === INTERRUPT).map((w) => w[1]),\n };\n }\n}\n\ntype ChannelKey = string | number | symbol;\n\nexport function* mapDebugCheckpoint<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n config: RunnableConfig,\n channels: Record<string, BaseChannel>,\n streamChannels: string | string[],\n metadata: CheckpointMetadata,\n tasks: readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n parentConfig: RunnableConfig | undefined,\n outputKeys: ChannelKey | ChannelKey[]\n) {\n function formatConfig(config: RunnableConfig) {\n // https://stackoverflow.com/a/78298178\n type CamelToSnake<\n T extends string,\n A extends string = \"\",\n > = T extends `${infer F}${infer R}`\n ? CamelToSnake<\n R,\n `${A}${F extends Lowercase<F> ? F : `_${Lowercase<F>}`}`\n >\n : A;\n\n // make sure the config is consistent with Python\n const pyConfig: Partial<\n Record<CamelToSnake<keyof RunnableConfig>, unknown>\n > = {};\n\n if (config.callbacks != null) pyConfig.callbacks = config.callbacks;\n if (config.configurable != null)\n pyConfig.configurable = config.configurable;\n if (config.maxConcurrency != null)\n pyConfig.max_concurrency = config.maxConcurrency;\n\n if (config.metadata != null) pyConfig.metadata = config.metadata;\n if (config.recursionLimit != null)\n pyConfig.recursion_limit = config.recursionLimit;\n if (config.runId != null) pyConfig.run_id = config.runId;\n if (config.runName != null) pyConfig.run_name = config.runName;\n if (config.tags != null) pyConfig.tags = config.tags;\n\n return pyConfig;\n }\n\n const parentNs = config.configurable?.checkpoint_ns;\n const taskStates: Record<string, RunnableConfig | StateSnapshot> = {};\n\n for (const task of tasks) {\n const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];\n if (!candidates.find(findSubgraphPregel)) continue;\n\n let taskNs = `${task.name as string}:${task.id}`;\n if (parentNs) taskNs = `${parentNs}|${taskNs}`;\n\n taskStates[task.id] = {\n configurable: {\n thread_id: config.configurable?.thread_id,\n checkpoint_ns: taskNs,\n },\n };\n }\n\n yield {\n config: formatConfig(config),\n values: readChannels(channels, streamChannels),\n metadata,\n next: tasks.map((task) => task.name),\n tasks: tasksWithWrites(tasks, pendingWrites, taskStates, outputKeys),\n parentConfig: parentConfig ? formatConfig(parentConfig) : undefined,\n };\n}\n\nexport function tasksWithWrites<N extends PropertyKey, C extends PropertyKey>(\n tasks: PregelTaskDescription[] | readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n states: Record<string, RunnableConfig | StateSnapshot> | undefined,\n outputKeys: ChannelKey[] | ChannelKey\n): PregelTaskDescription[] {\n return tasks.map((task): PregelTaskDescription => {\n const error = pendingWrites.find(\n ([id, n]) => id === task.id && n === ERROR\n )?.[2];\n\n const interrupts = pendingWrites\n .filter(([id, n]) => id === task.id && n === INTERRUPT)\n .map(([, , v]) => v) as Interrupt[];\n\n const result = (() => {\n if (error || interrupts.length || !pendingWrites.length) return undefined;\n\n const idx = pendingWrites.findIndex(\n ([tid, n]) => tid === task.id && n === RETURN\n );\n\n if (idx >= 0) return pendingWrites[idx][2];\n\n if (typeof outputKeys === \"string\") {\n return pendingWrites.find(\n ([tid, n]) => tid === task.id && n === outputKeys\n )?.[2];\n }\n\n if (Array.isArray(outputKeys)) {\n const results = pendingWrites\n .filter(([tid, n]) => tid === task.id && outputKeys.includes(n))\n .map(([, n, v]) => [n, v] as PendingWrite<C>);\n\n if (!results.length) return undefined;\n return mapTaskResultWrites(results);\n }\n\n return undefined;\n })();\n\n if (error) {\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n error,\n interrupts,\n result,\n };\n }\n\n const taskState = states?.[task.id];\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n interrupts,\n ...(taskState !== undefined ? { state: taskState } : {}),\n result,\n };\n });\n}\n\nexport function printStepCheckpoint(\n step: number,\n channels: Record<string, BaseChannel<unknown>>,\n whitelist: string[]\n): void {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:checkpoint]`)}`,\n `\\x1b[1m State at the end of step ${step}:\\x1b[0m\\n`,\n JSON.stringify(readChannels(channels, whitelist), null, 2),\n ].join(\"\")\n );\n}\n\nexport function printStepTasks<N extends PropertyKey, C extends PropertyKey>(\n step: number,\n nextTasks: readonly PregelExecutableTask<N, C>[]\n): void {\n const nTasks = nextTasks.length;\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:tasks]`)}`,\n `\\x1b[1m Starting step ${step} with ${nTasks} task${\n nTasks === 1 ? \"\" : \"s\"\n }:\\x1b[0m\\n`,\n nextTasks\n .map(\n (task) =>\n `- ${wrap(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(\n task.input,\n null,\n 2\n )}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n\nexport function printStepWrites(\n step: number,\n writes: PendingWrite[],\n whitelist: string[]\n): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const byChannel: Record<string, any[]> = {};\n\n for (const [channel, value] of writes) {\n if (whitelist.includes(channel)) {\n if (!byChannel[channel]) {\n byChannel[channel] = [];\n }\n byChannel[channel].push(value);\n }\n }\n\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:writes]`)}`,\n `\\x1b[1m Finished step ${step} with writes to ${\n Object.keys(byChannel).length\n } channel${Object.keys(byChannel).length !== 1 ? \"s\" : \"\"}:\\x1b[0m\\n`,\n Object.entries(byChannel)\n .map(\n ([name, vals]) =>\n `- ${wrap(COLORS_MAP.yellow, name)} -> ${vals\n .map((v) => JSON.stringify(v))\n .join(\", \")}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"debug.cjs","names":["EXCLUDED_METADATA_KEYS","filterToUserTags","INTERRUPT","findSubgraphPregel","readChannels"],"sources":["../../src/pregel/debug.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n CheckpointMetadata,\n CheckpointPendingWrite,\n EXCLUDED_METADATA_KEYS,\n PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { BaseChannel } from \"../channels/base.js\";\nimport {\n ERROR,\n Interrupt,\n INTERRUPT,\n RETURN,\n TAG_HIDDEN,\n} from \"../constants.js\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n PregelExecutableTask,\n PregelTaskDescription,\n StateSnapshot,\n} from \"./types.js\";\nimport { readChannels } from \"./io.js\";\nimport { findSubgraphPregel } from \"./utils/subgraph.js\";\nimport { filterToUserTags } from \"./utils/config.js\";\n\ntype ConsoleColors = {\n start: string;\n end: string;\n};\n\ntype ConsoleColorMap = {\n [key: string]: ConsoleColors;\n};\n\nconst COLORS_MAP: ConsoleColorMap = {\n blue: {\n start: \"\\x1b[34m\",\n end: \"\\x1b[0m\",\n },\n green: {\n start: \"\\x1b[32m\",\n end: \"\\x1b[0m\",\n },\n yellow: {\n start: \"\\x1b[33;1m\",\n end: \"\\x1b[0m\",\n },\n};\n\n/**\n * Wrap some text in a color for printing to the console.\n */\nexport const wrap = (color: ConsoleColors, text: string): string =>\n `${color.start}${text}${color.end}`;\n\nexport function printCheckpoint<Value>(\n step: number,\n channels: Record<string, BaseChannel<Value>>\n) {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, \"[langgraph/checkpoint]\")}`,\n `Finishing step ${step}. Channel values:\\n`,\n `\\n${JSON.stringify(\n Object.fromEntries(_readChannels<Value>(channels)),\n null,\n 2\n )}`,\n ].join(\"\")\n );\n}\n\nexport function* _readChannels<Value>(\n channels: Record<string, BaseChannel<Value>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): IterableIterator<[string, any]> {\n for (const [name, channel] of Object.entries(channels)) {\n try {\n yield [name, channel.get()];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // Skip the channel if it's empty\n continue;\n } else {\n throw error; // Re-throw the error if it's not an EmptyChannelError\n }\n }\n }\n}\n\n/**\n * Build the user-meaningful metadata to forward on a task's stream payload.\n *\n * Drops langgraph's internal framework keys ({@link EXCLUDED_METADATA_KEYS}) —\n * which are redundant with the task's own fields and namespace — while keeping\n * keys like `lc_agent_name`, `ls_integration`, and any user-supplied metadata.\n * Filtered config tags are folded in under `tags`, mirroring the messages\n * stream handler. Returns `undefined` when there is nothing to forward.\n */\nfunction buildTaskMetadata(\n config: RunnableConfig | undefined\n): Record<string, unknown> | undefined {\n if (config == null) return undefined;\n const metadata: Record<string, unknown> = {};\n if (config.metadata != null) {\n for (const [key, value] of Object.entries(config.metadata)) {\n if (!EXCLUDED_METADATA_KEYS.has(key)) metadata[key] = value;\n }\n }\n const filteredTags = filterToUserTags(config.tags);\n if (filteredTags != null) metadata.tags = filteredTags;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nexport function* mapDebugTasks<N extends PropertyKey, C extends PropertyKey>(\n tasks: readonly PregelExecutableTask<N, C>[]\n) {\n for (const { id, name, input, config, triggers, writes } of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n\n const interrupts = writes\n .filter(([writeId, n]) => {\n return writeId === id && n === INTERRUPT;\n })\n .map(([, v]) => {\n return v;\n });\n const payload: {\n id: string;\n name: N;\n input: unknown;\n triggers: string[];\n interrupts: unknown[];\n metadata?: Record<string, unknown>;\n } = { id, name, input, triggers, interrupts };\n const metadata = buildTaskMetadata(config);\n if (metadata != null) payload.metadata = metadata;\n yield payload;\n }\n}\n\nfunction isMultipleChannelWrite(\n value: unknown\n): value is { $writes: unknown[] } {\n if (typeof value !== \"object\" || value === null) return false;\n return \"$writes\" in value && Array.isArray(value.$writes);\n}\n\nfunction mapTaskResultWrites(writes: PendingWrite<unknown>[]) {\n const result: Record<string, unknown> = {};\n\n for (const [channel, value] of writes) {\n const strChannel = String(channel);\n\n if (strChannel in result) {\n const channelWrites = isMultipleChannelWrite(result[strChannel])\n ? result[strChannel].$writes\n : [result[strChannel]];\n\n channelWrites.push(value);\n result[strChannel] = { $writes: channelWrites };\n } else {\n result[strChannel] = value;\n }\n }\n return result;\n}\n\nexport function* mapDebugTaskResults<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n tasks: readonly [PregelExecutableTask<N, C>, PendingWrite<C>[]][],\n streamChannels: PropertyKey | Array<PropertyKey>\n) {\n for (const [{ id, name, config }, writes] of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n yield {\n id,\n name,\n result: mapTaskResultWrites(\n writes.filter(([channel]) => {\n return Array.isArray(streamChannels)\n ? streamChannels.includes(channel)\n : channel === streamChannels;\n })\n ),\n interrupts: writes.filter((w) => w[0] === INTERRUPT).map((w) => w[1]),\n };\n }\n}\n\ntype ChannelKey = string | number | symbol;\n\nexport function* mapDebugCheckpoint<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n config: RunnableConfig,\n channels: Record<string, BaseChannel>,\n streamChannels: string | string[],\n metadata: CheckpointMetadata,\n tasks: readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n parentConfig: RunnableConfig | undefined,\n outputKeys: ChannelKey | ChannelKey[]\n) {\n function formatConfig(config: RunnableConfig) {\n // https://stackoverflow.com/a/78298178\n type CamelToSnake<\n T extends string,\n A extends string = \"\",\n > = T extends `${infer F}${infer R}`\n ? CamelToSnake<\n R,\n `${A}${F extends Lowercase<F> ? F : `_${Lowercase<F>}`}`\n >\n : A;\n\n // make sure the config is consistent with Python\n const pyConfig: Partial<\n Record<CamelToSnake<keyof RunnableConfig>, unknown>\n > = {};\n\n if (config.callbacks != null) pyConfig.callbacks = config.callbacks;\n if (config.configurable != null)\n pyConfig.configurable = config.configurable;\n if (config.maxConcurrency != null)\n pyConfig.max_concurrency = config.maxConcurrency;\n\n if (config.metadata != null) pyConfig.metadata = config.metadata;\n if (config.recursionLimit != null)\n pyConfig.recursion_limit = config.recursionLimit;\n if (config.runId != null) pyConfig.run_id = config.runId;\n if (config.runName != null) pyConfig.run_name = config.runName;\n if (config.tags != null) pyConfig.tags = config.tags;\n\n return pyConfig;\n }\n\n const parentNs = config.configurable?.checkpoint_ns;\n const taskStates: Record<string, RunnableConfig | StateSnapshot> = {};\n\n for (const task of tasks) {\n const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];\n if (!candidates.find(findSubgraphPregel)) continue;\n\n let taskNs = `${task.name as string}:${task.id}`;\n if (parentNs) taskNs = `${parentNs}|${taskNs}`;\n\n taskStates[task.id] = {\n configurable: {\n thread_id: config.configurable?.thread_id,\n checkpoint_ns: taskNs,\n },\n };\n }\n\n yield {\n config: formatConfig(config),\n values: readChannels(channels, streamChannels),\n metadata,\n next: tasks.map((task) => task.name),\n tasks: tasksWithWrites(tasks, pendingWrites, taskStates, outputKeys),\n parentConfig: parentConfig ? formatConfig(parentConfig) : undefined,\n };\n}\n\nexport function tasksWithWrites<N extends PropertyKey, C extends PropertyKey>(\n tasks: PregelTaskDescription[] | readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n states: Record<string, RunnableConfig | StateSnapshot> | undefined,\n outputKeys: ChannelKey[] | ChannelKey\n): PregelTaskDescription[] {\n return tasks.map((task): PregelTaskDescription => {\n const error = pendingWrites.find(\n ([id, n]) => id === task.id && n === ERROR\n )?.[2];\n\n const interrupts = pendingWrites\n .filter(([id, n]) => id === task.id && n === INTERRUPT)\n .map(([, , v]) => v) as Interrupt[];\n\n const result = (() => {\n if (error || interrupts.length || !pendingWrites.length) return undefined;\n\n const idx = pendingWrites.findIndex(\n ([tid, n]) => tid === task.id && n === RETURN\n );\n\n if (idx >= 0) return pendingWrites[idx][2];\n\n if (typeof outputKeys === \"string\") {\n return pendingWrites.find(\n ([tid, n]) => tid === task.id && n === outputKeys\n )?.[2];\n }\n\n if (Array.isArray(outputKeys)) {\n const results = pendingWrites\n .filter(([tid, n]) => tid === task.id && outputKeys.includes(n))\n .map(([, n, v]) => [n, v] as PendingWrite<C>);\n\n if (!results.length) return undefined;\n return mapTaskResultWrites(results);\n }\n\n return undefined;\n })();\n\n if (error) {\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n error,\n interrupts,\n result,\n };\n }\n\n const taskState = states?.[task.id];\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n interrupts,\n ...(taskState !== undefined ? { state: taskState } : {}),\n result,\n };\n });\n}\n\nexport function printStepCheckpoint(\n step: number,\n channels: Record<string, BaseChannel<unknown>>,\n whitelist: string[]\n): void {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:checkpoint]`)}`,\n `\\x1b[1m State at the end of step ${step}:\\x1b[0m\\n`,\n JSON.stringify(readChannels(channels, whitelist), null, 2),\n ].join(\"\")\n );\n}\n\nexport function printStepTasks<N extends PropertyKey, C extends PropertyKey>(\n step: number,\n nextTasks: readonly PregelExecutableTask<N, C>[]\n): void {\n const nTasks = nextTasks.length;\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:tasks]`)}`,\n `\\x1b[1m Starting step ${step} with ${nTasks} task${\n nTasks === 1 ? \"\" : \"s\"\n }:\\x1b[0m\\n`,\n nextTasks\n .map(\n (task) =>\n `- ${wrap(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(\n task.input,\n null,\n 2\n )}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n\nexport function printStepWrites(\n step: number,\n writes: PendingWrite[],\n whitelist: string[]\n): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const byChannel: Record<string, any[]> = {};\n\n for (const [channel, value] of writes) {\n if (whitelist.includes(channel)) {\n if (!byChannel[channel]) {\n byChannel[channel] = [];\n }\n byChannel[channel].push(value);\n }\n }\n\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:writes]`)}`,\n `\\x1b[1m Finished step ${step} with writes to ${\n Object.keys(byChannel).length\n } channel${Object.keys(byChannel).length !== 1 ? \"s\" : \"\"}:\\x1b[0m\\n`,\n Object.entries(byChannel)\n .map(\n ([name, vals]) =>\n `- ${wrap(COLORS_MAP.yellow, name)} -> ${vals\n .map((v) => JSON.stringify(v))\n .join(\", \")}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { INTERRUPT } from "../constants.js";
2
+ import "../errors.js";
2
3
  import { filterToUserTags } from "./utils/config.js";
3
4
  import { readChannels } from "./io.js";
4
5
  import { findSubgraphPregel } from "./utils/subgraph.js";
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","names":[],"sources":["../../src/pregel/debug.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n CheckpointMetadata,\n CheckpointPendingWrite,\n EXCLUDED_METADATA_KEYS,\n PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { BaseChannel } from \"../channels/base.js\";\nimport {\n ERROR,\n Interrupt,\n INTERRUPT,\n RETURN,\n TAG_HIDDEN,\n} from \"../constants.js\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n PregelExecutableTask,\n PregelTaskDescription,\n StateSnapshot,\n} from \"./types.js\";\nimport { readChannels } from \"./io.js\";\nimport { findSubgraphPregel } from \"./utils/subgraph.js\";\nimport { filterToUserTags } from \"./utils/config.js\";\n\ntype ConsoleColors = {\n start: string;\n end: string;\n};\n\ntype ConsoleColorMap = {\n [key: string]: ConsoleColors;\n};\n\nconst COLORS_MAP: ConsoleColorMap = {\n blue: {\n start: \"\\x1b[34m\",\n end: \"\\x1b[0m\",\n },\n green: {\n start: \"\\x1b[32m\",\n end: \"\\x1b[0m\",\n },\n yellow: {\n start: \"\\x1b[33;1m\",\n end: \"\\x1b[0m\",\n },\n};\n\n/**\n * Wrap some text in a color for printing to the console.\n */\nexport const wrap = (color: ConsoleColors, text: string): string =>\n `${color.start}${text}${color.end}`;\n\nexport function printCheckpoint<Value>(\n step: number,\n channels: Record<string, BaseChannel<Value>>\n) {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, \"[langgraph/checkpoint]\")}`,\n `Finishing step ${step}. Channel values:\\n`,\n `\\n${JSON.stringify(\n Object.fromEntries(_readChannels<Value>(channels)),\n null,\n 2\n )}`,\n ].join(\"\")\n );\n}\n\nexport function* _readChannels<Value>(\n channels: Record<string, BaseChannel<Value>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): IterableIterator<[string, any]> {\n for (const [name, channel] of Object.entries(channels)) {\n try {\n yield [name, channel.get()];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // Skip the channel if it's empty\n continue;\n } else {\n throw error; // Re-throw the error if it's not an EmptyChannelError\n }\n }\n }\n}\n\n/**\n * Build the user-meaningful metadata to forward on a task's stream payload.\n *\n * Drops langgraph's internal framework keys ({@link EXCLUDED_METADATA_KEYS}) —\n * which are redundant with the task's own fields and namespace — while keeping\n * keys like `lc_agent_name`, `ls_integration`, and any user-supplied metadata.\n * Filtered config tags are folded in under `tags`, mirroring the messages\n * stream handler. Returns `undefined` when there is nothing to forward.\n */\nfunction buildTaskMetadata(\n config: RunnableConfig | undefined\n): Record<string, unknown> | undefined {\n if (config == null) return undefined;\n const metadata: Record<string, unknown> = {};\n if (config.metadata != null) {\n for (const [key, value] of Object.entries(config.metadata)) {\n if (!EXCLUDED_METADATA_KEYS.has(key)) metadata[key] = value;\n }\n }\n const filteredTags = filterToUserTags(config.tags);\n if (filteredTags != null) metadata.tags = filteredTags;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nexport function* mapDebugTasks<N extends PropertyKey, C extends PropertyKey>(\n tasks: readonly PregelExecutableTask<N, C>[]\n) {\n for (const { id, name, input, config, triggers, writes } of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n\n const interrupts = writes\n .filter(([writeId, n]) => {\n return writeId === id && n === INTERRUPT;\n })\n .map(([, v]) => {\n return v;\n });\n const payload: {\n id: string;\n name: N;\n input: unknown;\n triggers: string[];\n interrupts: unknown[];\n metadata?: Record<string, unknown>;\n } = { id, name, input, triggers, interrupts };\n const metadata = buildTaskMetadata(config);\n if (metadata != null) payload.metadata = metadata;\n yield payload;\n }\n}\n\nfunction isMultipleChannelWrite(\n value: unknown\n): value is { $writes: unknown[] } {\n if (typeof value !== \"object\" || value === null) return false;\n return \"$writes\" in value && Array.isArray(value.$writes);\n}\n\nfunction mapTaskResultWrites(writes: PendingWrite<unknown>[]) {\n const result: Record<string, unknown> = {};\n\n for (const [channel, value] of writes) {\n const strChannel = String(channel);\n\n if (strChannel in result) {\n const channelWrites = isMultipleChannelWrite(result[strChannel])\n ? result[strChannel].$writes\n : [result[strChannel]];\n\n channelWrites.push(value);\n result[strChannel] = { $writes: channelWrites };\n } else {\n result[strChannel] = value;\n }\n }\n return result;\n}\n\nexport function* mapDebugTaskResults<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n tasks: readonly [PregelExecutableTask<N, C>, PendingWrite<C>[]][],\n streamChannels: PropertyKey | Array<PropertyKey>\n) {\n for (const [{ id, name, config }, writes] of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n yield {\n id,\n name,\n result: mapTaskResultWrites(\n writes.filter(([channel]) => {\n return Array.isArray(streamChannels)\n ? streamChannels.includes(channel)\n : channel === streamChannels;\n })\n ),\n interrupts: writes.filter((w) => w[0] === INTERRUPT).map((w) => w[1]),\n };\n }\n}\n\ntype ChannelKey = string | number | symbol;\n\nexport function* mapDebugCheckpoint<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n config: RunnableConfig,\n channels: Record<string, BaseChannel>,\n streamChannels: string | string[],\n metadata: CheckpointMetadata,\n tasks: readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n parentConfig: RunnableConfig | undefined,\n outputKeys: ChannelKey | ChannelKey[]\n) {\n function formatConfig(config: RunnableConfig) {\n // https://stackoverflow.com/a/78298178\n type CamelToSnake<\n T extends string,\n A extends string = \"\",\n > = T extends `${infer F}${infer R}`\n ? CamelToSnake<\n R,\n `${A}${F extends Lowercase<F> ? F : `_${Lowercase<F>}`}`\n >\n : A;\n\n // make sure the config is consistent with Python\n const pyConfig: Partial<\n Record<CamelToSnake<keyof RunnableConfig>, unknown>\n > = {};\n\n if (config.callbacks != null) pyConfig.callbacks = config.callbacks;\n if (config.configurable != null)\n pyConfig.configurable = config.configurable;\n if (config.maxConcurrency != null)\n pyConfig.max_concurrency = config.maxConcurrency;\n\n if (config.metadata != null) pyConfig.metadata = config.metadata;\n if (config.recursionLimit != null)\n pyConfig.recursion_limit = config.recursionLimit;\n if (config.runId != null) pyConfig.run_id = config.runId;\n if (config.runName != null) pyConfig.run_name = config.runName;\n if (config.tags != null) pyConfig.tags = config.tags;\n\n return pyConfig;\n }\n\n const parentNs = config.configurable?.checkpoint_ns;\n const taskStates: Record<string, RunnableConfig | StateSnapshot> = {};\n\n for (const task of tasks) {\n const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];\n if (!candidates.find(findSubgraphPregel)) continue;\n\n let taskNs = `${task.name as string}:${task.id}`;\n if (parentNs) taskNs = `${parentNs}|${taskNs}`;\n\n taskStates[task.id] = {\n configurable: {\n thread_id: config.configurable?.thread_id,\n checkpoint_ns: taskNs,\n },\n };\n }\n\n yield {\n config: formatConfig(config),\n values: readChannels(channels, streamChannels),\n metadata,\n next: tasks.map((task) => task.name),\n tasks: tasksWithWrites(tasks, pendingWrites, taskStates, outputKeys),\n parentConfig: parentConfig ? formatConfig(parentConfig) : undefined,\n };\n}\n\nexport function tasksWithWrites<N extends PropertyKey, C extends PropertyKey>(\n tasks: PregelTaskDescription[] | readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n states: Record<string, RunnableConfig | StateSnapshot> | undefined,\n outputKeys: ChannelKey[] | ChannelKey\n): PregelTaskDescription[] {\n return tasks.map((task): PregelTaskDescription => {\n const error = pendingWrites.find(\n ([id, n]) => id === task.id && n === ERROR\n )?.[2];\n\n const interrupts = pendingWrites\n .filter(([id, n]) => id === task.id && n === INTERRUPT)\n .map(([, , v]) => v) as Interrupt[];\n\n const result = (() => {\n if (error || interrupts.length || !pendingWrites.length) return undefined;\n\n const idx = pendingWrites.findIndex(\n ([tid, n]) => tid === task.id && n === RETURN\n );\n\n if (idx >= 0) return pendingWrites[idx][2];\n\n if (typeof outputKeys === \"string\") {\n return pendingWrites.find(\n ([tid, n]) => tid === task.id && n === outputKeys\n )?.[2];\n }\n\n if (Array.isArray(outputKeys)) {\n const results = pendingWrites\n .filter(([tid, n]) => tid === task.id && outputKeys.includes(n))\n .map(([, n, v]) => [n, v] as PendingWrite<C>);\n\n if (!results.length) return undefined;\n return mapTaskResultWrites(results);\n }\n\n return undefined;\n })();\n\n if (error) {\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n error,\n interrupts,\n result,\n };\n }\n\n const taskState = states?.[task.id];\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n interrupts,\n ...(taskState !== undefined ? { state: taskState } : {}),\n result,\n };\n });\n}\n\nexport function printStepCheckpoint(\n step: number,\n channels: Record<string, BaseChannel<unknown>>,\n whitelist: string[]\n): void {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:checkpoint]`)}`,\n `\\x1b[1m State at the end of step ${step}:\\x1b[0m\\n`,\n JSON.stringify(readChannels(channels, whitelist), null, 2),\n ].join(\"\")\n );\n}\n\nexport function printStepTasks<N extends PropertyKey, C extends PropertyKey>(\n step: number,\n nextTasks: readonly PregelExecutableTask<N, C>[]\n): void {\n const nTasks = nextTasks.length;\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:tasks]`)}`,\n `\\x1b[1m Starting step ${step} with ${nTasks} task${\n nTasks === 1 ? \"\" : \"s\"\n }:\\x1b[0m\\n`,\n nextTasks\n .map(\n (task) =>\n `- ${wrap(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(\n task.input,\n null,\n 2\n )}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n\nexport function printStepWrites(\n step: number,\n writes: PendingWrite[],\n whitelist: string[]\n): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const byChannel: Record<string, any[]> = {};\n\n for (const [channel, value] of writes) {\n if (whitelist.includes(channel)) {\n if (!byChannel[channel]) {\n byChannel[channel] = [];\n }\n byChannel[channel].push(value);\n }\n }\n\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:writes]`)}`,\n `\\x1b[1m Finished step ${step} with writes to ${\n Object.keys(byChannel).length\n } channel${Object.keys(byChannel).length !== 1 ? \"s\" : \"\"}:\\x1b[0m\\n`,\n Object.entries(byChannel)\n .map(\n ([name, vals]) =>\n `- ${wrap(COLORS_MAP.yellow, name)} -> ${vals\n .map((v) => JSON.stringify(v))\n .join(\", \")}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"debug.js","names":[],"sources":["../../src/pregel/debug.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n CheckpointMetadata,\n CheckpointPendingWrite,\n EXCLUDED_METADATA_KEYS,\n PendingWrite,\n} from \"@langchain/langgraph-checkpoint\";\nimport { BaseChannel } from \"../channels/base.js\";\nimport {\n ERROR,\n Interrupt,\n INTERRUPT,\n RETURN,\n TAG_HIDDEN,\n} from \"../constants.js\";\nimport { EmptyChannelError } from \"../errors.js\";\nimport {\n PregelExecutableTask,\n PregelTaskDescription,\n StateSnapshot,\n} from \"./types.js\";\nimport { readChannels } from \"./io.js\";\nimport { findSubgraphPregel } from \"./utils/subgraph.js\";\nimport { filterToUserTags } from \"./utils/config.js\";\n\ntype ConsoleColors = {\n start: string;\n end: string;\n};\n\ntype ConsoleColorMap = {\n [key: string]: ConsoleColors;\n};\n\nconst COLORS_MAP: ConsoleColorMap = {\n blue: {\n start: \"\\x1b[34m\",\n end: \"\\x1b[0m\",\n },\n green: {\n start: \"\\x1b[32m\",\n end: \"\\x1b[0m\",\n },\n yellow: {\n start: \"\\x1b[33;1m\",\n end: \"\\x1b[0m\",\n },\n};\n\n/**\n * Wrap some text in a color for printing to the console.\n */\nexport const wrap = (color: ConsoleColors, text: string): string =>\n `${color.start}${text}${color.end}`;\n\nexport function printCheckpoint<Value>(\n step: number,\n channels: Record<string, BaseChannel<Value>>\n) {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, \"[langgraph/checkpoint]\")}`,\n `Finishing step ${step}. Channel values:\\n`,\n `\\n${JSON.stringify(\n Object.fromEntries(_readChannels<Value>(channels)),\n null,\n 2\n )}`,\n ].join(\"\")\n );\n}\n\nexport function* _readChannels<Value>(\n channels: Record<string, BaseChannel<Value>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): IterableIterator<[string, any]> {\n for (const [name, channel] of Object.entries(channels)) {\n try {\n yield [name, channel.get()];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.name === EmptyChannelError.unminifiable_name) {\n // Skip the channel if it's empty\n continue;\n } else {\n throw error; // Re-throw the error if it's not an EmptyChannelError\n }\n }\n }\n}\n\n/**\n * Build the user-meaningful metadata to forward on a task's stream payload.\n *\n * Drops langgraph's internal framework keys ({@link EXCLUDED_METADATA_KEYS}) —\n * which are redundant with the task's own fields and namespace — while keeping\n * keys like `lc_agent_name`, `ls_integration`, and any user-supplied metadata.\n * Filtered config tags are folded in under `tags`, mirroring the messages\n * stream handler. Returns `undefined` when there is nothing to forward.\n */\nfunction buildTaskMetadata(\n config: RunnableConfig | undefined\n): Record<string, unknown> | undefined {\n if (config == null) return undefined;\n const metadata: Record<string, unknown> = {};\n if (config.metadata != null) {\n for (const [key, value] of Object.entries(config.metadata)) {\n if (!EXCLUDED_METADATA_KEYS.has(key)) metadata[key] = value;\n }\n }\n const filteredTags = filterToUserTags(config.tags);\n if (filteredTags != null) metadata.tags = filteredTags;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nexport function* mapDebugTasks<N extends PropertyKey, C extends PropertyKey>(\n tasks: readonly PregelExecutableTask<N, C>[]\n) {\n for (const { id, name, input, config, triggers, writes } of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n\n const interrupts = writes\n .filter(([writeId, n]) => {\n return writeId === id && n === INTERRUPT;\n })\n .map(([, v]) => {\n return v;\n });\n const payload: {\n id: string;\n name: N;\n input: unknown;\n triggers: string[];\n interrupts: unknown[];\n metadata?: Record<string, unknown>;\n } = { id, name, input, triggers, interrupts };\n const metadata = buildTaskMetadata(config);\n if (metadata != null) payload.metadata = metadata;\n yield payload;\n }\n}\n\nfunction isMultipleChannelWrite(\n value: unknown\n): value is { $writes: unknown[] } {\n if (typeof value !== \"object\" || value === null) return false;\n return \"$writes\" in value && Array.isArray(value.$writes);\n}\n\nfunction mapTaskResultWrites(writes: PendingWrite<unknown>[]) {\n const result: Record<string, unknown> = {};\n\n for (const [channel, value] of writes) {\n const strChannel = String(channel);\n\n if (strChannel in result) {\n const channelWrites = isMultipleChannelWrite(result[strChannel])\n ? result[strChannel].$writes\n : [result[strChannel]];\n\n channelWrites.push(value);\n result[strChannel] = { $writes: channelWrites };\n } else {\n result[strChannel] = value;\n }\n }\n return result;\n}\n\nexport function* mapDebugTaskResults<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n tasks: readonly [PregelExecutableTask<N, C>, PendingWrite<C>[]][],\n streamChannels: PropertyKey | Array<PropertyKey>\n) {\n for (const [{ id, name, config }, writes] of tasks) {\n if (config?.tags?.includes(TAG_HIDDEN)) continue;\n yield {\n id,\n name,\n result: mapTaskResultWrites(\n writes.filter(([channel]) => {\n return Array.isArray(streamChannels)\n ? streamChannels.includes(channel)\n : channel === streamChannels;\n })\n ),\n interrupts: writes.filter((w) => w[0] === INTERRUPT).map((w) => w[1]),\n };\n }\n}\n\ntype ChannelKey = string | number | symbol;\n\nexport function* mapDebugCheckpoint<\n N extends PropertyKey,\n C extends PropertyKey,\n>(\n config: RunnableConfig,\n channels: Record<string, BaseChannel>,\n streamChannels: string | string[],\n metadata: CheckpointMetadata,\n tasks: readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n parentConfig: RunnableConfig | undefined,\n outputKeys: ChannelKey | ChannelKey[]\n) {\n function formatConfig(config: RunnableConfig) {\n // https://stackoverflow.com/a/78298178\n type CamelToSnake<\n T extends string,\n A extends string = \"\",\n > = T extends `${infer F}${infer R}`\n ? CamelToSnake<\n R,\n `${A}${F extends Lowercase<F> ? F : `_${Lowercase<F>}`}`\n >\n : A;\n\n // make sure the config is consistent with Python\n const pyConfig: Partial<\n Record<CamelToSnake<keyof RunnableConfig>, unknown>\n > = {};\n\n if (config.callbacks != null) pyConfig.callbacks = config.callbacks;\n if (config.configurable != null)\n pyConfig.configurable = config.configurable;\n if (config.maxConcurrency != null)\n pyConfig.max_concurrency = config.maxConcurrency;\n\n if (config.metadata != null) pyConfig.metadata = config.metadata;\n if (config.recursionLimit != null)\n pyConfig.recursion_limit = config.recursionLimit;\n if (config.runId != null) pyConfig.run_id = config.runId;\n if (config.runName != null) pyConfig.run_name = config.runName;\n if (config.tags != null) pyConfig.tags = config.tags;\n\n return pyConfig;\n }\n\n const parentNs = config.configurable?.checkpoint_ns;\n const taskStates: Record<string, RunnableConfig | StateSnapshot> = {};\n\n for (const task of tasks) {\n const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];\n if (!candidates.find(findSubgraphPregel)) continue;\n\n let taskNs = `${task.name as string}:${task.id}`;\n if (parentNs) taskNs = `${parentNs}|${taskNs}`;\n\n taskStates[task.id] = {\n configurable: {\n thread_id: config.configurable?.thread_id,\n checkpoint_ns: taskNs,\n },\n };\n }\n\n yield {\n config: formatConfig(config),\n values: readChannels(channels, streamChannels),\n metadata,\n next: tasks.map((task) => task.name),\n tasks: tasksWithWrites(tasks, pendingWrites, taskStates, outputKeys),\n parentConfig: parentConfig ? formatConfig(parentConfig) : undefined,\n };\n}\n\nexport function tasksWithWrites<N extends PropertyKey, C extends PropertyKey>(\n tasks: PregelTaskDescription[] | readonly PregelExecutableTask<N, C>[],\n pendingWrites: CheckpointPendingWrite[],\n states: Record<string, RunnableConfig | StateSnapshot> | undefined,\n outputKeys: ChannelKey[] | ChannelKey\n): PregelTaskDescription[] {\n return tasks.map((task): PregelTaskDescription => {\n const error = pendingWrites.find(\n ([id, n]) => id === task.id && n === ERROR\n )?.[2];\n\n const interrupts = pendingWrites\n .filter(([id, n]) => id === task.id && n === INTERRUPT)\n .map(([, , v]) => v) as Interrupt[];\n\n const result = (() => {\n if (error || interrupts.length || !pendingWrites.length) return undefined;\n\n const idx = pendingWrites.findIndex(\n ([tid, n]) => tid === task.id && n === RETURN\n );\n\n if (idx >= 0) return pendingWrites[idx][2];\n\n if (typeof outputKeys === \"string\") {\n return pendingWrites.find(\n ([tid, n]) => tid === task.id && n === outputKeys\n )?.[2];\n }\n\n if (Array.isArray(outputKeys)) {\n const results = pendingWrites\n .filter(([tid, n]) => tid === task.id && outputKeys.includes(n))\n .map(([, n, v]) => [n, v] as PendingWrite<C>);\n\n if (!results.length) return undefined;\n return mapTaskResultWrites(results);\n }\n\n return undefined;\n })();\n\n if (error) {\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n error,\n interrupts,\n result,\n };\n }\n\n const taskState = states?.[task.id];\n return {\n id: task.id,\n name: task.name as string,\n path: task.path,\n interrupts,\n ...(taskState !== undefined ? { state: taskState } : {}),\n result,\n };\n });\n}\n\nexport function printStepCheckpoint(\n step: number,\n channels: Record<string, BaseChannel<unknown>>,\n whitelist: string[]\n): void {\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:checkpoint]`)}`,\n `\\x1b[1m State at the end of step ${step}:\\x1b[0m\\n`,\n JSON.stringify(readChannels(channels, whitelist), null, 2),\n ].join(\"\")\n );\n}\n\nexport function printStepTasks<N extends PropertyKey, C extends PropertyKey>(\n step: number,\n nextTasks: readonly PregelExecutableTask<N, C>[]\n): void {\n const nTasks = nextTasks.length;\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:tasks]`)}`,\n `\\x1b[1m Starting step ${step} with ${nTasks} task${\n nTasks === 1 ? \"\" : \"s\"\n }:\\x1b[0m\\n`,\n nextTasks\n .map(\n (task) =>\n `- ${wrap(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(\n task.input,\n null,\n 2\n )}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n\nexport function printStepWrites(\n step: number,\n writes: PendingWrite[],\n whitelist: string[]\n): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const byChannel: Record<string, any[]> = {};\n\n for (const [channel, value] of writes) {\n if (whitelist.includes(channel)) {\n if (!byChannel[channel]) {\n byChannel[channel] = [];\n }\n byChannel[channel].push(value);\n }\n }\n\n console.log(\n [\n `${wrap(COLORS_MAP.blue, `[${step}:writes]`)}`,\n `\\x1b[1m Finished step ${step} with writes to ${\n Object.keys(byChannel).length\n } channel${Object.keys(byChannel).length !== 1 ? \"s\" : \"\"}:\\x1b[0m\\n`,\n Object.entries(byChannel)\n .map(\n ([name, vals]) =>\n `- ${wrap(COLORS_MAP.yellow, name)} -> ${vals\n .map((v) => JSON.stringify(v))\n .join(\", \")}`\n )\n .join(\"\\n\"),\n ].join(\"\")\n );\n}\n"],"mappings":"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"}
@@ -233,9 +233,11 @@ var PregelLoop = class PregelLoop {
233
233
  _resumeLoadedWrites = [];
234
234
  /** Tasks a resume handed loaded writes back to. */
235
235
  _reappliedTaskIds = /* @__PURE__ */ new Set();
236
+ /** Tasks that wrote during this run, the only ones exit mode saves at exit. */
237
+ _writtenTaskIds = /* @__PURE__ */ new Set();
236
238
  /**
237
- * An update or fork checkpoint addressed by `checkpoint_id` that the thread
238
- * has moved past, so it may already have children.
239
+ * A checkpoint addressed by `checkpoint_id` that the thread has moved past,
240
+ * so it may already have children.
239
241
  */
240
242
  addressedCheckpointSuperseded;
241
243
  /** Whether a real checkpoint was loaded from the saver at initialization. */
@@ -264,7 +266,9 @@ var PregelLoop = class PregelLoop {
264
266
  outputKeys;
265
267
  streamKeys;
266
268
  nodes;
267
- skipDoneTasks;
269
+ /** Whether the run points this loop at a checkpoint. */
270
+ addressed;
271
+ skipDoneTasks = true;
268
272
  prevCheckpointConfig;
269
273
  updatedChannels;
270
274
  status = "pending";
@@ -365,7 +369,7 @@ var PregelLoop = class PregelLoop {
365
369
  this.outputKeys = params.outputKeys;
366
370
  this.streamKeys = params.streamKeys;
367
371
  this.nodes = params.nodes;
368
- this.skipDoneTasks = params.skipDoneTasks;
372
+ this.addressed = params.addressed;
369
373
  this.store = params.store;
370
374
  this.cache = params.cache ? new AsyncBatchedCache(params.cache) : void 0;
371
375
  this.stream = params.stream;
@@ -387,7 +391,6 @@ var PregelLoop = class PregelLoop {
387
391
  static async initialize(params) {
388
392
  let { config, stream } = params;
389
393
  if (stream !== void 0 && config.configurable?.["__pregel_stream"] !== void 0) stream = require_stream.createDuplexStream(stream, config.configurable[require_constants.CONFIG_KEY_STREAM]);
390
- const skipDoneTasks = config.configurable ? !("checkpoint_id" in config.configurable) : true;
391
394
  const scratchpad = config.configurable?.[require_constants.CONFIG_KEY_SCRATCHPAD];
392
395
  if (config.configurable && scratchpad) {
393
396
  if (scratchpad.subgraphCounter > 0) config = require_index.patchConfigurable(config, { [require_constants.CONFIG_KEY_CHECKPOINT_NS]: [config.configurable[require_constants.CONFIG_KEY_CHECKPOINT_NS], scratchpad.subgraphCounter.toString()].join("|") });
@@ -400,6 +403,7 @@ var PregelLoop = class PregelLoop {
400
403
  });
401
404
  let checkpointConfig = config;
402
405
  if (config.configurable?.checkpoint_id === void 0 && config.configurable?.["checkpoint_map"] !== void 0 && config.configurable?.["checkpoint_map"]?.[config.configurable?.checkpoint_ns]) checkpointConfig = require_index.patchConfigurable(config, { checkpoint_id: config.configurable[require_constants.CONFIG_KEY_CHECKPOINT_MAP][config.configurable?.checkpoint_ns] });
406
+ const addressed = Boolean(checkpointConfig.configurable?.["checkpoint_id"] || config.configurable?.["__pregel_replay_state"]);
403
407
  const checkpointNamespace = checkpointNamespaceFromNs(config.configurable?.checkpoint_ns);
404
408
  let saved;
405
409
  let loadedLatest = false;
@@ -446,7 +450,7 @@ var PregelLoop = class PregelLoop {
446
450
  const superseded = await require_checkpoint.checkpointSuperseded(params.checkpointer, addressedConfig, saved);
447
451
  const isUpdateOrFork = checkpointMetadata.source === "update" || checkpointMetadata.source === "fork";
448
452
  resumeAtHead = addressedConfig.configurable?.checkpoint_id !== void 0 && !superseded && !isUpdateOrFork;
449
- addressedCheckpointSuperseded = superseded && isUpdateOrFork;
453
+ addressedCheckpointSuperseded = superseded;
450
454
  }
451
455
  const deltaWritesVersioned = Object.values(params.channelSpecs).some(require_base.isDeltaChannel) && (!hasPersistedParent || require_base.isDeltaWritesVersioned(saved.metadata));
452
456
  const channels = await require_base.channelsFromCheckpoint(params.channelSpecs, checkpoint, {
@@ -474,7 +478,7 @@ var PregelLoop = class PregelLoop {
474
478
  addressedCheckpointSuperseded,
475
479
  manager: params.manager,
476
480
  hasGraphCallbacks: params.hasGraphCallbacks,
477
- skipDoneTasks,
481
+ addressed,
478
482
  step,
479
483
  stop,
480
484
  checkpointPreviousVersions,
@@ -513,6 +517,7 @@ var PregelLoop = class PregelLoop {
513
517
  putWrites(taskId, writes, cached = false) {
514
518
  let writesCopy = writes;
515
519
  if (writesCopy.length === 0) return;
520
+ this._writtenTaskIds.add(taskId);
516
521
  const deltaWrites = ensureDeltaMessageIds(this.channels, writes);
517
522
  if (writesCopy.every(([key]) => key in _langchain_langgraph_checkpoint.WRITES_IDX_MAP)) writesCopy = Array.from(new Map(writesCopy.map((w) => [w[0], w])).values());
518
523
  let hasUntrackedChannels = false;
@@ -835,7 +840,8 @@ var PregelLoop = class PregelLoop {
835
840
  async _first(inputKeys) {
836
841
  const { configurable } = this.config;
837
842
  const inputIsCommand = require_constants.isCommand(this.input);
838
- const isTimeTraveling = this.isReplaying && (this.isNested && configurable?.["checkpoint_ns"] !== void 0 && configurable?.["checkpoint_ns"] !== "" && configurable?.["checkpoint_map"] !== void 0 && configurable["checkpoint_ns"] in configurable["checkpoint_map"] || !(inputIsCommand && this.input.resume != null || configurable?.["__pregel_resuming"] === true || this.resumeAtHead));
843
+ const isTimeTraveling = this.addressed && (this.isNested && configurable?.["checkpoint_ns"] !== void 0 && configurable?.["checkpoint_ns"] !== "" && configurable?.["checkpoint_map"] !== void 0 && configurable["checkpoint_ns"] in configurable["checkpoint_map"] || !(inputIsCommand && this.input.resume != null || configurable?.["__pregel_resuming"] === true || this.resumeAtHead));
844
+ this.skipDoneTasks = !(isTimeTraveling || this.addressedCheckpointSuperseded);
839
845
  const isUpdateOrFork = this.checkpointMetadata.source === "update" || this.checkpointMetadata.source === "fork";
840
846
  const forks = isTimeTraveling && (inputIsCommand || this.isResuming) && (!isUpdateOrFork || this.addressedCheckpointSuperseded);
841
847
  const carried = [];
@@ -1162,6 +1168,7 @@ var PregelLoop = class PregelLoop {
1162
1168
  });
1163
1169
  const byTask = {};
1164
1170
  for (const [tid, key, value] of this.checkpointPendingWrites) {
1171
+ if (!this._writtenTaskIds.has(tid)) continue;
1165
1172
  byTask[tid] ??= [];
1166
1173
  byTask[tid].push([key, value]);
1167
1174
  }