@langchain/langgraph 0.2.5 → 0.2.7

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.
@@ -40,7 +40,20 @@ class Branch {
40
40
  }
41
41
  compile(writer, reader) {
42
42
  return write_js_1.ChannelWrite.registerWriter(new utils_js_1.RunnableCallable({
43
- func: (input, config) => this._route(input, config, writer, reader),
43
+ func: async (input, config) => {
44
+ try {
45
+ return await this._route(input, config, writer, reader);
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ }
48
+ catch (e) {
49
+ // Detect & warn if NodeInterrupt is thrown in a conditional edge
50
+ if (e.name === errors_js_1.NodeInterrupt.unminifiable_name) {
51
+ console.warn("[WARN]: 'NodeInterrupt' thrown in conditional edge. This is likely a bug in your graph implementation.\n" +
52
+ "NodeInterrupt should only be thrown inside a node, not in edge conditions.");
53
+ }
54
+ throw e;
55
+ }
56
+ },
44
57
  }));
45
58
  }
46
59
  async _route(input, config, writer, reader) {
@@ -8,7 +8,7 @@ import { EphemeralValue } from "../channels/ephemeral_value.js";
8
8
  import { ChannelWrite, PASSTHROUGH } from "../pregel/write.js";
9
9
  import { _isSend, CHECKPOINT_NAMESPACE_SEPARATOR, TAG_HIDDEN, } from "../constants.js";
10
10
  import { RunnableCallable } from "../utils.js";
11
- import { InvalidUpdateError } from "../errors.js";
11
+ import { InvalidUpdateError, NodeInterrupt } from "../errors.js";
12
12
  /** Special reserved node name denoting the start of a graph. */
13
13
  export const START = "__start__";
14
14
  /** Special reserved node name denoting the end of a graph. */
@@ -37,7 +37,20 @@ export class Branch {
37
37
  }
38
38
  compile(writer, reader) {
39
39
  return ChannelWrite.registerWriter(new RunnableCallable({
40
- func: (input, config) => this._route(input, config, writer, reader),
40
+ func: async (input, config) => {
41
+ try {
42
+ return await this._route(input, config, writer, reader);
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ }
45
+ catch (e) {
46
+ // Detect & warn if NodeInterrupt is thrown in a conditional edge
47
+ if (e.name === NodeInterrupt.unminifiable_name) {
48
+ console.warn("[WARN]: 'NodeInterrupt' thrown in conditional edge. This is likely a bug in your graph implementation.\n" +
49
+ "NodeInterrupt should only be thrown inside a node, not in edge conditions.");
50
+ }
51
+ throw e;
52
+ }
53
+ },
41
54
  }));
42
55
  }
43
56
  async _route(input, config, writer, reader) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isConfiguredManagedValue = exports.isManagedValue = exports.ManagedValueMapping = exports.ChannelKeyPlaceholder = exports.WritableManagedValue = exports.ManagedValue = void 0;
3
+ exports.NoopManagedValue = exports.isConfiguredManagedValue = exports.isManagedValue = exports.ManagedValueMapping = exports.ChannelKeyPlaceholder = exports.WritableManagedValue = exports.ManagedValue = void 0;
4
4
  const constants_js_1 = require("../constants.cjs");
5
5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
6
  class ManagedValue {
@@ -161,3 +161,16 @@ function isConfiguredManagedValue(value) {
161
161
  return false;
162
162
  }
163
163
  exports.isConfiguredManagedValue = isConfiguredManagedValue;
164
+ /**
165
+ * No-op class used when getting state values, as managed values should never be returned
166
+ * in get state calls.
167
+ */
168
+ class NoopManagedValue extends ManagedValue {
169
+ call() { }
170
+ static async initialize(config,
171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ _args) {
173
+ return Promise.resolve(new NoopManagedValue(config));
174
+ }
175
+ }
176
+ exports.NoopManagedValue = NoopManagedValue;
@@ -28,3 +28,11 @@ export declare class ManagedValueMapping extends Map<string, ManagedValue<any>>
28
28
  }
29
29
  export declare function isManagedValue(value: unknown): value is typeof ManagedValue;
30
30
  export declare function isConfiguredManagedValue(value: unknown): value is ConfiguredManagedValue;
31
+ /**
32
+ * No-op class used when getting state values, as managed values should never be returned
33
+ * in get state calls.
34
+ */
35
+ export declare class NoopManagedValue extends ManagedValue {
36
+ call(): void;
37
+ static initialize(config: RunnableConfig, _args?: any): Promise<ManagedValue>;
38
+ }
@@ -153,3 +153,15 @@ export function isConfiguredManagedValue(value) {
153
153
  }
154
154
  return false;
155
155
  }
156
+ /**
157
+ * No-op class used when getting state values, as managed values should never be returned
158
+ * in get state calls.
159
+ */
160
+ export class NoopManagedValue extends ManagedValue {
161
+ call() { }
162
+ static async initialize(config,
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ _args) {
165
+ return Promise.resolve(new NoopManagedValue(config));
166
+ }
167
+ }
@@ -243,7 +243,8 @@ class Pregel extends runnables_1.Runnable {
243
243
  const saved = await this.checkpointer.getTuple(config);
244
244
  const checkpoint = saved ? saved.checkpoint : (0, langgraph_checkpoint_1.emptyCheckpoint)();
245
245
  const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
246
- const { managed } = await this.prepareSpecs(config);
246
+ // Pass `skipManaged: true` as managed values should not be returned in get state calls.
247
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
247
248
  const nextTasks = (0, algo_js_1._prepareNextTasks)(checkpoint, this.nodes, channels, managed, saved !== undefined ? saved.config : config, false, { step: saved ? (saved.metadata?.step ?? -1) + 1 : -1 });
248
249
  return {
249
250
  values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
@@ -262,7 +263,8 @@ class Pregel extends runnables_1.Runnable {
262
263
  if (!this.checkpointer) {
263
264
  throw new errors_js_1.GraphValueError("No checkpointer set");
264
265
  }
265
- const { managed } = await this.prepareSpecs(config);
266
+ // Pass `skipManaged: true` as managed values should not be returned in get state calls.
267
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
266
268
  for await (const saved of this.checkpointer.list(config, options)) {
267
269
  const channels = (0, base_js_1.emptyChannels)(this.channels, saved.checkpoint);
268
270
  const nextTasks = (0, algo_js_1._prepareNextTasks)(saved.checkpoint, this.nodes, channels, managed, saved.config, false, { step: -1 });
@@ -354,7 +356,8 @@ class Pregel extends runnables_1.Runnable {
354
356
  }
355
357
  // update channels
356
358
  const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
357
- const { managed } = await this.prepareSpecs(config);
359
+ // Pass `skipManaged: true` as managed values are not used/relevant in update state calls.
360
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
358
361
  // run all writers of the chosen node
359
362
  const writers = this.nodes[asNode].getWriters();
360
363
  if (!writers.length) {
@@ -467,7 +470,7 @@ class Pregel extends runnables_1.Runnable {
467
470
  async stream(input, options) {
468
471
  return super.stream(input, options);
469
472
  }
470
- async prepareSpecs(config) {
473
+ async prepareSpecs(config, options) {
471
474
  const configForManaged = (0, utils_js_2.patchConfigurable)(config, {
472
475
  [constants_js_1.CONFIG_KEY_STORE]: this.store,
473
476
  });
@@ -477,6 +480,12 @@ class Pregel extends runnables_1.Runnable {
477
480
  if ((0, base_js_1.isBaseChannel)(spec)) {
478
481
  channelSpecs[name] = spec;
479
482
  }
483
+ else if (options?.skipManaged) {
484
+ managedSpecs[name] = {
485
+ cls: base_js_2.NoopManagedValue,
486
+ params: { config: {} },
487
+ };
488
+ }
480
489
  else {
481
490
  managedSpecs[name] = spec;
482
491
  }
@@ -105,7 +105,9 @@ export declare class Pregel<Nn extends StrRecord<string, PregelNode>, Cc extends
105
105
  * @param options.debug Whether to print debug information during execution.
106
106
  */
107
107
  stream(input: PregelInputType, options?: Partial<PregelOptions<Nn, Cc>>): Promise<IterableReadableStream<PregelOutputType>>;
108
- protected prepareSpecs(config: RunnableConfig): Promise<{
108
+ protected prepareSpecs(config: RunnableConfig, options?: {
109
+ skipManaged?: boolean;
110
+ }): Promise<{
109
111
  channelSpecs: Record<string, BaseChannel<unknown, unknown, unknown>>;
110
112
  managed: ManagedValueMapping;
111
113
  }>;
@@ -13,7 +13,7 @@ import { _prepareNextTasks, _localRead, _applyWrites, } from "./algo.js";
13
13
  import { _coerceToDict, getNewChannelVersions } from "./utils.js";
14
14
  import { PregelLoop } from "./loop.js";
15
15
  import { executeTasksWithRetry } from "./retry.js";
16
- import { ChannelKeyPlaceholder, isConfiguredManagedValue, ManagedValueMapping, } from "../managed/base.js";
16
+ import { ChannelKeyPlaceholder, isConfiguredManagedValue, ManagedValueMapping, NoopManagedValue, } from "../managed/base.js";
17
17
  import { patchConfigurable } from "../utils.js";
18
18
  function isString(value) {
19
19
  return typeof value === "string";
@@ -239,7 +239,8 @@ export class Pregel extends Runnable {
239
239
  const saved = await this.checkpointer.getTuple(config);
240
240
  const checkpoint = saved ? saved.checkpoint : emptyCheckpoint();
241
241
  const channels = emptyChannels(this.channels, checkpoint);
242
- const { managed } = await this.prepareSpecs(config);
242
+ // Pass `skipManaged: true` as managed values should not be returned in get state calls.
243
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
243
244
  const nextTasks = _prepareNextTasks(checkpoint, this.nodes, channels, managed, saved !== undefined ? saved.config : config, false, { step: saved ? (saved.metadata?.step ?? -1) + 1 : -1 });
244
245
  return {
245
246
  values: readChannels(channels, this.streamChannelsAsIs),
@@ -258,7 +259,8 @@ export class Pregel extends Runnable {
258
259
  if (!this.checkpointer) {
259
260
  throw new GraphValueError("No checkpointer set");
260
261
  }
261
- const { managed } = await this.prepareSpecs(config);
262
+ // Pass `skipManaged: true` as managed values should not be returned in get state calls.
263
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
262
264
  for await (const saved of this.checkpointer.list(config, options)) {
263
265
  const channels = emptyChannels(this.channels, saved.checkpoint);
264
266
  const nextTasks = _prepareNextTasks(saved.checkpoint, this.nodes, channels, managed, saved.config, false, { step: -1 });
@@ -350,7 +352,8 @@ export class Pregel extends Runnable {
350
352
  }
351
353
  // update channels
352
354
  const channels = emptyChannels(this.channels, checkpoint);
353
- const { managed } = await this.prepareSpecs(config);
355
+ // Pass `skipManaged: true` as managed values are not used/relevant in update state calls.
356
+ const { managed } = await this.prepareSpecs(config, { skipManaged: true });
354
357
  // run all writers of the chosen node
355
358
  const writers = this.nodes[asNode].getWriters();
356
359
  if (!writers.length) {
@@ -463,7 +466,7 @@ export class Pregel extends Runnable {
463
466
  async stream(input, options) {
464
467
  return super.stream(input, options);
465
468
  }
466
- async prepareSpecs(config) {
469
+ async prepareSpecs(config, options) {
467
470
  const configForManaged = patchConfigurable(config, {
468
471
  [CONFIG_KEY_STORE]: this.store,
469
472
  });
@@ -473,6 +476,12 @@ export class Pregel extends Runnable {
473
476
  if (isBaseChannel(spec)) {
474
477
  channelSpecs[name] = spec;
475
478
  }
479
+ else if (options?.skipManaged) {
480
+ managedSpecs[name] = {
481
+ cls: NoopManagedValue,
482
+ params: { config: {} },
483
+ };
484
+ }
476
485
  else {
477
486
  managedSpecs[name] = spec;
478
487
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {