@langchain/langgraph 0.2.31 → 0.2.32

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.
@@ -65,7 +65,7 @@ export declare class Graph<N extends string = typeof END, RunInput = any, RunOut
65
65
  }): CompiledGraph<N>;
66
66
  validate(interrupt?: string[]): void;
67
67
  }
68
- export declare class CompiledGraph<N extends string, State = any, Update = any, ConfigurableFieldType extends Record<string, any> = Record<string, any>> extends Pregel<Record<N | typeof START, PregelNode<State, Update>>, Record<N | typeof START | typeof END | string, BaseChannel>, ConfigurableFieldType & Record<string, any>, Update, State> {
68
+ export declare class CompiledGraph<N extends string, State = any, Update = any, ConfigurableFieldType extends Record<string, any> = Record<string, any>, InputType = any, OutputType = any> extends Pregel<Record<N | typeof START, PregelNode<State, Update>>, Record<N | typeof START | typeof END | string, BaseChannel>, ConfigurableFieldType & Record<string, any>, InputType, OutputType> {
69
69
  NodeType: N;
70
70
  RunInput: State;
71
71
  RunOutput: Update;
@@ -128,7 +128,7 @@ export declare class StateGraph<SD extends StateDefinition | unknown, S = SD ext
128
128
  * Should not be instantiated directly, only using the StateGraph `.compile()`
129
129
  * instance method.
130
130
  */
131
- export declare class CompiledStateGraph<S, U, N extends string = typeof START, I extends StateDefinition = StateDefinition, O extends StateDefinition = StateDefinition, C extends StateDefinition = StateDefinition> extends CompiledGraph<N, S, U, StateType<C>> {
131
+ export declare class CompiledStateGraph<S, U, N extends string = typeof START, I extends StateDefinition = StateDefinition, O extends StateDefinition = StateDefinition, C extends StateDefinition = StateDefinition> extends CompiledGraph<N, S, U, StateType<C>, UpdateType<I>, StateType<O>> {
132
132
  builder: StateGraph<unknown, S, U, N, I, O, C>;
133
133
  attachNode(key: typeof START, node?: never): void;
134
134
  attachNode(key: N, node: StateGraphNodeSpec<S, U>): void;
@@ -345,6 +345,19 @@ class Pregel extends runnables_1.Runnable {
345
345
  });
346
346
  }
347
347
  }
348
+ // apply pending writes
349
+ const nullWrites = (saved.pendingWrites ?? [])
350
+ .filter((w) => w[0] === constants_js_1.NULL_TASK_ID)
351
+ .map((w) => w.slice(1));
352
+ if (nullWrites.length > 0) {
353
+ (0, algo_js_1._applyWrites)(saved.checkpoint, channels, [
354
+ {
355
+ name: constants_js_1.INPUT,
356
+ writes: nullWrites,
357
+ triggers: [],
358
+ },
359
+ ]);
360
+ }
348
361
  // assemble the state snapshot
349
362
  return {
350
363
  values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
@@ -505,7 +518,7 @@ class Pregel extends runnables_1.Runnable {
505
518
  // apply null writes
506
519
  const nullWrites = (saved.pendingWrites || [])
507
520
  .filter((w) => w[0] === constants_js_1.NULL_TASK_ID)
508
- .flatMap((w) => w.slice(1));
521
+ .map((w) => w.slice(1));
509
522
  if (nullWrites.length > 0) {
510
523
  (0, algo_js_1._applyWrites)(saved.checkpoint, channels, [
511
524
  {
@@ -547,6 +560,45 @@ class Pregel extends runnables_1.Runnable {
547
560
  }, {});
548
561
  return (0, index_js_1.patchCheckpointMap)(nextConfig, saved ? saved.metadata : undefined);
549
562
  }
563
+ // apply pending writes, if not on specific checkpoint
564
+ if (config.configurable?.checkpoint_id === undefined &&
565
+ saved?.pendingWrites !== undefined &&
566
+ saved.pendingWrites.length > 0) {
567
+ // tasks for this checkpoint
568
+ const nextTasks = (0, algo_js_1._prepareNextTasks)(checkpoint, saved.pendingWrites, this.nodes, channels, managed, saved.config, true, {
569
+ store: this.store,
570
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
571
+ checkpointer: this.checkpointer,
572
+ step: (saved.metadata?.step ?? -1) + 1,
573
+ });
574
+ // apply null writes
575
+ const nullWrites = (saved.pendingWrites ?? [])
576
+ .filter((w) => w[0] === constants_js_1.NULL_TASK_ID)
577
+ .map((w) => w.slice(1));
578
+ if (nullWrites.length > 0) {
579
+ (0, algo_js_1._applyWrites)(saved.checkpoint, channels, [
580
+ {
581
+ name: constants_js_1.INPUT,
582
+ writes: nullWrites,
583
+ triggers: [],
584
+ },
585
+ ]);
586
+ }
587
+ // apply writes
588
+ for (const [tid, k, v] of saved.pendingWrites) {
589
+ if ([constants_js_1.ERROR, constants_js_1.INTERRUPT, langgraph_checkpoint_1.SCHEDULED].includes(k) ||
590
+ nextTasks[tid] === undefined) {
591
+ continue;
592
+ }
593
+ nextTasks[tid].writes.push([k, v]);
594
+ }
595
+ const tasks = Object.values(nextTasks).filter((task) => {
596
+ return task.writes.length > 0;
597
+ });
598
+ if (tasks.length > 0) {
599
+ (0, algo_js_1._applyWrites)(checkpoint, channels, tasks);
600
+ }
601
+ }
550
602
  const nonNullVersion = Object.values(checkpoint.versions_seen)
551
603
  .map((seenVersions) => {
552
604
  return Object.values(seenVersions);
@@ -341,6 +341,19 @@ export class Pregel extends Runnable {
341
341
  });
342
342
  }
343
343
  }
344
+ // apply pending writes
345
+ const nullWrites = (saved.pendingWrites ?? [])
346
+ .filter((w) => w[0] === NULL_TASK_ID)
347
+ .map((w) => w.slice(1));
348
+ if (nullWrites.length > 0) {
349
+ _applyWrites(saved.checkpoint, channels, [
350
+ {
351
+ name: INPUT,
352
+ writes: nullWrites,
353
+ triggers: [],
354
+ },
355
+ ]);
356
+ }
344
357
  // assemble the state snapshot
345
358
  return {
346
359
  values: readChannels(channels, this.streamChannelsAsIs),
@@ -501,7 +514,7 @@ export class Pregel extends Runnable {
501
514
  // apply null writes
502
515
  const nullWrites = (saved.pendingWrites || [])
503
516
  .filter((w) => w[0] === NULL_TASK_ID)
504
- .flatMap((w) => w.slice(1));
517
+ .map((w) => w.slice(1));
505
518
  if (nullWrites.length > 0) {
506
519
  _applyWrites(saved.checkpoint, channels, [
507
520
  {
@@ -543,6 +556,45 @@ export class Pregel extends Runnable {
543
556
  }, {});
544
557
  return patchCheckpointMap(nextConfig, saved ? saved.metadata : undefined);
545
558
  }
559
+ // apply pending writes, if not on specific checkpoint
560
+ if (config.configurable?.checkpoint_id === undefined &&
561
+ saved?.pendingWrites !== undefined &&
562
+ saved.pendingWrites.length > 0) {
563
+ // tasks for this checkpoint
564
+ const nextTasks = _prepareNextTasks(checkpoint, saved.pendingWrites, this.nodes, channels, managed, saved.config, true, {
565
+ store: this.store,
566
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
567
+ checkpointer: this.checkpointer,
568
+ step: (saved.metadata?.step ?? -1) + 1,
569
+ });
570
+ // apply null writes
571
+ const nullWrites = (saved.pendingWrites ?? [])
572
+ .filter((w) => w[0] === NULL_TASK_ID)
573
+ .map((w) => w.slice(1));
574
+ if (nullWrites.length > 0) {
575
+ _applyWrites(saved.checkpoint, channels, [
576
+ {
577
+ name: INPUT,
578
+ writes: nullWrites,
579
+ triggers: [],
580
+ },
581
+ ]);
582
+ }
583
+ // apply writes
584
+ for (const [tid, k, v] of saved.pendingWrites) {
585
+ if ([ERROR, INTERRUPT, SCHEDULED].includes(k) ||
586
+ nextTasks[tid] === undefined) {
587
+ continue;
588
+ }
589
+ nextTasks[tid].writes.push([k, v]);
590
+ }
591
+ const tasks = Object.values(nextTasks).filter((task) => {
592
+ return task.writes.length > 0;
593
+ });
594
+ if (tasks.length > 0) {
595
+ _applyWrites(checkpoint, channels, tasks);
596
+ }
597
+ }
546
598
  const nonNullVersion = Object.values(checkpoint.versions_seen)
547
599
  .map((seenVersions) => {
548
600
  return Object.values(seenVersions);
@@ -72,17 +72,16 @@ function* mapCommand(cmd, pendingWrites) {
72
72
  throw new Error(`In Command.send, expected Send or string, got ${typeof send}`);
73
73
  }
74
74
  }
75
- // TODO: handle goto str for state graph
76
75
  }
77
76
  if (cmd.resume) {
78
77
  if (typeof cmd.resume === "object" &&
79
- !!cmd.resume &&
80
78
  Object.keys(cmd.resume).length &&
81
79
  Object.keys(cmd.resume).every(uuid_1.validate)) {
82
80
  for (const [tid, resume] of Object.entries(cmd.resume)) {
83
- // Find existing resume values for this task ID
84
- const existing = (pendingWrites.find(([id, type]) => id === tid && type === constants_js_1.RESUME)?.[2] ?? []);
85
- // Ensure we have an array and append the resume value
81
+ const existing = pendingWrites
82
+ .filter((w) => w[0] === tid && w[1] === constants_js_1.RESUME)
83
+ .map((w) => w[2])
84
+ .slice(0, 1) ?? [];
86
85
  existing.push(resume);
87
86
  yield [tid, constants_js_1.RESUME, existing];
88
87
  }
@@ -7,7 +7,7 @@ export declare function readChannels<C extends PropertyKey>(channels: Record<C,
7
7
  /**
8
8
  * Map input chunk to a sequence of pending writes in the form (channel, value).
9
9
  */
10
- export declare function mapCommand(cmd: Command, pendingWrites: CheckpointPendingWrite<string>[]): Generator<[string, string, unknown]>;
10
+ export declare function mapCommand(cmd: Command, pendingWrites: CheckpointPendingWrite[]): Generator<[string, string, unknown]>;
11
11
  /**
12
12
  * Map input chunk to a sequence of pending writes in the form [channel, value].
13
13
  */
package/dist/pregel/io.js CHANGED
@@ -67,17 +67,16 @@ export function* mapCommand(cmd, pendingWrites) {
67
67
  throw new Error(`In Command.send, expected Send or string, got ${typeof send}`);
68
68
  }
69
69
  }
70
- // TODO: handle goto str for state graph
71
70
  }
72
71
  if (cmd.resume) {
73
72
  if (typeof cmd.resume === "object" &&
74
- !!cmd.resume &&
75
73
  Object.keys(cmd.resume).length &&
76
74
  Object.keys(cmd.resume).every(validate)) {
77
75
  for (const [tid, resume] of Object.entries(cmd.resume)) {
78
- // Find existing resume values for this task ID
79
- const existing = (pendingWrites.find(([id, type]) => id === tid && type === RESUME)?.[2] ?? []);
80
- // Ensure we have an array and append the resume value
76
+ const existing = pendingWrites
77
+ .filter((w) => w[0] === tid && w[1] === RESUME)
78
+ .map((w) => w[2])
79
+ .slice(0, 1) ?? [];
81
80
  existing.push(resume);
82
81
  yield [tid, RESUME, existing];
83
82
  }
@@ -409,14 +409,9 @@ class PregelLoop {
409
409
  }
410
410
  // save writes
411
411
  for (const [c, v] of writesCopy) {
412
- if (c in langgraph_checkpoint_1.WRITES_IDX_MAP) {
413
- const idx = this.checkpointPendingWrites.findIndex((w) => w[0] === taskId && w[1] === c);
414
- if (idx !== -1) {
415
- this.checkpointPendingWrites[idx] = [taskId, c, v];
416
- }
417
- else {
418
- this.checkpointPendingWrites.push([taskId, c, v]);
419
- }
412
+ const idx = this.checkpointPendingWrites.findIndex((w) => w[0] === taskId && w[1] === c);
413
+ if (c in langgraph_checkpoint_1.WRITES_IDX_MAP && idx !== -1) {
414
+ this.checkpointPendingWrites[idx] = [taskId, c, v];
420
415
  }
421
416
  else {
422
417
  this.checkpointPendingWrites.push([taskId, c, v]);
@@ -586,7 +581,7 @@ class PregelLoop {
586
581
  /**
587
582
  * Resuming from previous checkpoint requires
588
583
  * - finding a previous checkpoint
589
- * - receiving None input (outer graph) or RESUMING flag (subgraph)
584
+ * - receiving null input (outer graph) or RESUMING flag (subgraph)
590
585
  */
591
586
  async _first(inputKeys) {
592
587
  const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
@@ -610,6 +605,19 @@ class PregelLoop {
610
605
  this.putWrites(tid, ws);
611
606
  }
612
607
  }
608
+ // apply null writes
609
+ const nullWrites = (this.checkpointPendingWrites ?? [])
610
+ .filter((w) => w[0] === constants_js_1.NULL_TASK_ID)
611
+ .map((w) => w.slice(1));
612
+ if (nullWrites.length > 0) {
613
+ (0, algo_js_1._applyWrites)(this.checkpoint, this.channels, [
614
+ {
615
+ name: constants_js_1.INPUT,
616
+ writes: nullWrites,
617
+ triggers: [],
618
+ },
619
+ ], this.checkpointerGetNextVersion);
620
+ }
613
621
  if (isResuming) {
614
622
  for (const channelName of Object.keys(this.channels)) {
615
623
  if (this.checkpoint.channel_versions[channelName] !== undefined) {
@@ -116,7 +116,7 @@ export declare class PregelLoop {
116
116
  /**
117
117
  * Resuming from previous checkpoint requires
118
118
  * - finding a previous checkpoint
119
- * - receiving None input (outer graph) or RESUMING flag (subgraph)
119
+ * - receiving null input (outer graph) or RESUMING flag (subgraph)
120
120
  */
121
121
  protected _first(inputKeys: string | string[]): Promise<void>;
122
122
  protected _emit(values: [StreamMode, unknown][]): void;
@@ -1,7 +1,7 @@
1
1
  import { IterableReadableStream } from "@langchain/core/utils/stream";
2
2
  import { copyCheckpoint, emptyCheckpoint, AsyncBatchedStore, WRITES_IDX_MAP, } from "@langchain/langgraph-checkpoint";
3
3
  import { createCheckpoint, emptyChannels, } from "../channels/base.js";
4
- import { _isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, RESUME, TAG_HIDDEN, } from "../constants.js";
4
+ import { _isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, NULL_TASK_ID, RESUME, TAG_HIDDEN, } from "../constants.js";
5
5
  import { _applyWrites, _prepareNextTasks, increment, shouldInterrupt, } from "./algo.js";
6
6
  import { gatherIterator, gatherIteratorSync, prefixGenerator, } from "../utils.js";
7
7
  import { mapCommand, mapInput, mapOutputUpdates, mapOutputValues, readChannels, } from "./io.js";
@@ -405,14 +405,9 @@ export class PregelLoop {
405
405
  }
406
406
  // save writes
407
407
  for (const [c, v] of writesCopy) {
408
- if (c in WRITES_IDX_MAP) {
409
- const idx = this.checkpointPendingWrites.findIndex((w) => w[0] === taskId && w[1] === c);
410
- if (idx !== -1) {
411
- this.checkpointPendingWrites[idx] = [taskId, c, v];
412
- }
413
- else {
414
- this.checkpointPendingWrites.push([taskId, c, v]);
415
- }
408
+ const idx = this.checkpointPendingWrites.findIndex((w) => w[0] === taskId && w[1] === c);
409
+ if (c in WRITES_IDX_MAP && idx !== -1) {
410
+ this.checkpointPendingWrites[idx] = [taskId, c, v];
416
411
  }
417
412
  else {
418
413
  this.checkpointPendingWrites.push([taskId, c, v]);
@@ -582,7 +577,7 @@ export class PregelLoop {
582
577
  /**
583
578
  * Resuming from previous checkpoint requires
584
579
  * - finding a previous checkpoint
585
- * - receiving None input (outer graph) or RESUMING flag (subgraph)
580
+ * - receiving null input (outer graph) or RESUMING flag (subgraph)
586
581
  */
587
582
  async _first(inputKeys) {
588
583
  const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
@@ -606,6 +601,19 @@ export class PregelLoop {
606
601
  this.putWrites(tid, ws);
607
602
  }
608
603
  }
604
+ // apply null writes
605
+ const nullWrites = (this.checkpointPendingWrites ?? [])
606
+ .filter((w) => w[0] === NULL_TASK_ID)
607
+ .map((w) => w.slice(1));
608
+ if (nullWrites.length > 0) {
609
+ _applyWrites(this.checkpoint, this.channels, [
610
+ {
611
+ name: INPUT,
612
+ writes: nullWrites,
613
+ triggers: [],
614
+ },
615
+ ], this.checkpointerGetNextVersion);
616
+ }
609
617
  if (isResuming) {
610
618
  for (const channelName of Object.keys(this.channels)) {
611
619
  if (this.checkpoint.channel_versions[channelName] !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.2.31",
3
+ "version": "0.2.32",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {