@langchain/langgraph 1.4.8 → 1.4.10

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.
@@ -2,6 +2,15 @@ const require_errors = require("../errors.cjs");
2
2
  const require_base = require("./base.cjs");
3
3
  //#region src/channels/topic.ts
4
4
  /**
5
+ * Detect the `[seen, values]` Topic checkpoint shape.
6
+ *
7
+ * Used for `unique: true` topics (current) and pre-flat JS checkpoints
8
+ * (legacy). Flat Python-parity checkpoints are a single values list.
9
+ */
10
+ function isUniqueTopicCheckpoint(checkpoint) {
11
+ return Array.isArray(checkpoint) && checkpoint.length === 2 && Array.isArray(checkpoint[0]) && Array.isArray(checkpoint[1]);
12
+ }
13
+ /**
5
14
  * A configurable PubSub Topic.
6
15
  */
7
16
  var Topic = class Topic extends require_base.BaseChannel {
@@ -22,10 +31,14 @@ var Topic = class Topic extends require_base.BaseChannel {
22
31
  unique: this.unique,
23
32
  accumulate: this.accumulate
24
33
  });
25
- if (typeof checkpoint !== "undefined") {
34
+ if (typeof checkpoint === "undefined") return empty;
35
+ if (isUniqueTopicCheckpoint(checkpoint)) {
26
36
  empty.seen = new Set(checkpoint[0]);
27
- empty.values = checkpoint[1];
37
+ empty.values = [...checkpoint[1]];
38
+ return empty;
28
39
  }
40
+ empty.values = [...checkpoint];
41
+ if (this.unique) empty.seen = new Set(empty.values);
29
42
  return empty;
30
43
  }
31
44
  update(values) {
@@ -51,8 +64,20 @@ var Topic = class Topic extends require_base.BaseChannel {
51
64
  if (this.values.length === 0) throw new require_errors.EmptyChannelError();
52
65
  return this.values;
53
66
  }
67
+ /**
68
+ * Checkpoint Topic state.
69
+ *
70
+ * Default / Host path (`unique: false`, including `__pregel_tasks`): flat
71
+ * values list, matching Python Topic. Previously this always returned
72
+ * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python
73
+ * checkpointer rejected it.
74
+ *
75
+ * When `unique: true`, keep `[seen, values]` so dedupe history that outlives
76
+ * the current buffer still survives resume.
77
+ */
54
78
  checkpoint() {
55
- return [[...this.seen], this.values];
79
+ if (this.unique) return [[...this.seen], [...this.values]];
80
+ return [...this.values];
56
81
  }
57
82
  isAvailable() {
58
83
  return this.values.length !== 0;
@@ -1 +1 @@
1
- {"version":3,"file":"topic.cjs","names":["BaseChannel","EmptyChannelError"],"sources":["../../src/channels/topic.ts"],"sourcesContent":["import { EmptyChannelError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\n/**\n * A configurable PubSub Topic.\n */\nexport class Topic<Value> extends BaseChannel<\n Array<Value>,\n Value | Value[],\n [Value[], Value[]]\n> {\n lc_graph_name = \"Topic\";\n\n unique = false;\n\n accumulate = false;\n\n seen: Set<Value>;\n\n values: Value[];\n\n constructor(fields?: {\n /**\n * Whether to only add unique values to the topic. If `true`, only unique values (using reference equality) will be added to the topic.\n */\n unique?: boolean;\n /**\n * Whether to accumulate values across steps. If `false`, the channel will be emptied after each step.\n */\n accumulate?: boolean;\n }) {\n super();\n\n this.unique = fields?.unique ?? this.unique;\n this.accumulate = fields?.accumulate ?? this.accumulate;\n // State\n this.seen = new Set<Value>();\n this.values = [];\n }\n\n public fromCheckpoint(checkpoint?: [Value[], Value[]]) {\n const empty = new Topic<Value>({\n unique: this.unique,\n accumulate: this.accumulate,\n });\n if (typeof checkpoint !== \"undefined\") {\n empty.seen = new Set(checkpoint[0]);\n // eslint-disable-next-line prefer-destructuring\n empty.values = checkpoint[1];\n }\n return empty as this;\n }\n\n public update(values: Array<Value | Value[]>): boolean {\n let updated = false;\n if (!this.accumulate) {\n updated = this.values.length > 0;\n this.values = [];\n }\n const flatValues = values.flat() as Value[];\n if (flatValues.length > 0) {\n if (this.unique) {\n for (const value of flatValues) {\n if (!this.seen.has(value)) {\n updated = true;\n this.seen.add(value);\n this.values.push(value);\n }\n }\n } else {\n updated = true;\n this.values.push(...flatValues);\n }\n }\n return updated;\n }\n\n public get(): Array<Value> {\n if (this.values.length === 0) {\n throw new EmptyChannelError();\n }\n return this.values;\n }\n\n public checkpoint(): [Value[], Value[]] {\n return [[...this.seen], this.values];\n }\n\n isAvailable(): boolean {\n return this.values.length !== 0;\n }\n}\n"],"mappings":";;;;;;AAMA,IAAa,QAAb,MAAa,cAAqBA,aAAAA,YAIhC;CACA,gBAAgB;CAEhB,SAAS;CAET,aAAa;CAEb;CAEA;CAEA,YAAY,QAST;AACD,SAAO;AAEP,OAAK,SAAS,QAAQ,UAAU,KAAK;AACrC,OAAK,aAAa,QAAQ,cAAc,KAAK;AAE7C,OAAK,uBAAO,IAAI,KAAY;AAC5B,OAAK,SAAS,EAAE;;CAGlB,eAAsB,YAAiC;EACrD,MAAM,QAAQ,IAAI,MAAa;GAC7B,QAAQ,KAAK;GACb,YAAY,KAAK;GAClB,CAAC;AACF,MAAI,OAAO,eAAe,aAAa;AACrC,SAAM,OAAO,IAAI,IAAI,WAAW,GAAG;AAEnC,SAAM,SAAS,WAAW;;AAE5B,SAAO;;CAGT,OAAc,QAAyC;EACrD,IAAI,UAAU;AACd,MAAI,CAAC,KAAK,YAAY;AACpB,aAAU,KAAK,OAAO,SAAS;AAC/B,QAAK,SAAS,EAAE;;EAElB,MAAM,aAAa,OAAO,MAAM;AAChC,MAAI,WAAW,SAAS,EACtB,KAAI,KAAK;QACF,MAAM,SAAS,WAClB,KAAI,CAAC,KAAK,KAAK,IAAI,MAAM,EAAE;AACzB,cAAU;AACV,SAAK,KAAK,IAAI,MAAM;AACpB,SAAK,OAAO,KAAK,MAAM;;SAGtB;AACL,aAAU;AACV,QAAK,OAAO,KAAK,GAAG,WAAW;;AAGnC,SAAO;;CAGT,MAA2B;AACzB,MAAI,KAAK,OAAO,WAAW,EACzB,OAAM,IAAIC,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAAwC;AACtC,SAAO,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,OAAO;;CAGtC,cAAuB;AACrB,SAAO,KAAK,OAAO,WAAW"}
1
+ {"version":3,"file":"topic.cjs","names":["BaseChannel","EmptyChannelError"],"sources":["../../src/channels/topic.ts"],"sourcesContent":["import { EmptyChannelError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\n/** JS Topic checkpoint when `unique` is set: `[seen, values]`. */\ntype UniqueTopicCheckpoint<Value> = [Value[], Value[]];\n\n/**\n * Detect the `[seen, values]` Topic checkpoint shape.\n *\n * Used for `unique: true` topics (current) and pre-flat JS checkpoints\n * (legacy). Flat Python-parity checkpoints are a single values list.\n */\nfunction isUniqueTopicCheckpoint<Value>(\n checkpoint: unknown\n): checkpoint is UniqueTopicCheckpoint<Value> {\n return (\n Array.isArray(checkpoint) &&\n checkpoint.length === 2 &&\n Array.isArray(checkpoint[0]) &&\n Array.isArray(checkpoint[1])\n );\n}\n\n/**\n * A configurable PubSub Topic.\n */\nexport class Topic<Value> extends BaseChannel<\n Array<Value>,\n Value | Value[],\n Value[] | UniqueTopicCheckpoint<Value>\n> {\n lc_graph_name = \"Topic\";\n\n unique = false;\n\n accumulate = false;\n\n seen: Set<Value>;\n\n values: Value[];\n\n constructor(fields?: {\n /**\n * Whether to only add unique values to the topic. If `true`, only unique values (using reference equality) will be added to the topic.\n */\n unique?: boolean;\n /**\n * Whether to accumulate values across steps. If `false`, the channel will be emptied after each step.\n */\n accumulate?: boolean;\n }) {\n super();\n\n this.unique = fields?.unique ?? this.unique;\n this.accumulate = fields?.accumulate ?? this.accumulate;\n // State\n this.seen = new Set<Value>();\n this.values = [];\n }\n\n public fromCheckpoint(checkpoint?: Value[] | UniqueTopicCheckpoint<Value>) {\n const empty = new Topic<Value>({\n unique: this.unique,\n accumulate: this.accumulate,\n });\n if (typeof checkpoint === \"undefined\") {\n return empty as this;\n }\n // `unique: true` (and legacy pre-flat) checkpoints are `[seen, values]`.\n if (isUniqueTopicCheckpoint<Value>(checkpoint)) {\n empty.seen = new Set(checkpoint[0]);\n empty.values = [...checkpoint[1]];\n return empty as this;\n }\n empty.values = [...checkpoint];\n // Flat checkpoints have no historical `seen`. Seed from the current\n // buffer so `unique: true` still de-dupes values present after restore.\n if (this.unique) {\n empty.seen = new Set(empty.values);\n }\n return empty as this;\n }\n\n public update(values: Array<Value | Value[]>): boolean {\n let updated = false;\n if (!this.accumulate) {\n updated = this.values.length > 0;\n this.values = [];\n }\n const flatValues = values.flat() as Value[];\n if (flatValues.length > 0) {\n if (this.unique) {\n for (const value of flatValues) {\n if (!this.seen.has(value)) {\n updated = true;\n this.seen.add(value);\n this.values.push(value);\n }\n }\n } else {\n updated = true;\n this.values.push(...flatValues);\n }\n }\n return updated;\n }\n\n public get(): Array<Value> {\n if (this.values.length === 0) {\n throw new EmptyChannelError();\n }\n return this.values;\n }\n\n /**\n * Checkpoint Topic state.\n *\n * Default / Host path (`unique: false`, including `__pregel_tasks`): flat\n * values list, matching Python Topic. Previously this always returned\n * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python\n * checkpointer rejected it.\n *\n * When `unique: true`, keep `[seen, values]` so dedupe history that outlives\n * the current buffer still survives resume.\n */\n public checkpoint(): Value[] | UniqueTopicCheckpoint<Value> {\n if (this.unique) {\n return [[...this.seen], [...this.values]];\n }\n return [...this.values];\n }\n\n isAvailable(): boolean {\n return this.values.length !== 0;\n }\n}\n"],"mappings":";;;;;;;;;AAYA,SAAS,wBACP,YAC4C;AAC5C,QACE,MAAM,QAAQ,WAAW,IACzB,WAAW,WAAW,KACtB,MAAM,QAAQ,WAAW,GAAG,IAC5B,MAAM,QAAQ,WAAW,GAAG;;;;;AAOhC,IAAa,QAAb,MAAa,cAAqBA,aAAAA,YAIhC;CACA,gBAAgB;CAEhB,SAAS;CAET,aAAa;CAEb;CAEA;CAEA,YAAY,QAST;AACD,SAAO;AAEP,OAAK,SAAS,QAAQ,UAAU,KAAK;AACrC,OAAK,aAAa,QAAQ,cAAc,KAAK;AAE7C,OAAK,uBAAO,IAAI,KAAY;AAC5B,OAAK,SAAS,EAAE;;CAGlB,eAAsB,YAAqD;EACzE,MAAM,QAAQ,IAAI,MAAa;GAC7B,QAAQ,KAAK;GACb,YAAY,KAAK;GAClB,CAAC;AACF,MAAI,OAAO,eAAe,YACxB,QAAO;AAGT,MAAI,wBAA+B,WAAW,EAAE;AAC9C,SAAM,OAAO,IAAI,IAAI,WAAW,GAAG;AACnC,SAAM,SAAS,CAAC,GAAG,WAAW,GAAG;AACjC,UAAO;;AAET,QAAM,SAAS,CAAC,GAAG,WAAW;AAG9B,MAAI,KAAK,OACP,OAAM,OAAO,IAAI,IAAI,MAAM,OAAO;AAEpC,SAAO;;CAGT,OAAc,QAAyC;EACrD,IAAI,UAAU;AACd,MAAI,CAAC,KAAK,YAAY;AACpB,aAAU,KAAK,OAAO,SAAS;AAC/B,QAAK,SAAS,EAAE;;EAElB,MAAM,aAAa,OAAO,MAAM;AAChC,MAAI,WAAW,SAAS,EACtB,KAAI,KAAK;QACF,MAAM,SAAS,WAClB,KAAI,CAAC,KAAK,KAAK,IAAI,MAAM,EAAE;AACzB,cAAU;AACV,SAAK,KAAK,IAAI,MAAM;AACpB,SAAK,OAAO,KAAK,MAAM;;SAGtB;AACL,aAAU;AACV,QAAK,OAAO,KAAK,GAAG,WAAW;;AAGnC,SAAO;;CAGT,MAA2B;AACzB,MAAI,KAAK,OAAO,WAAW,EACzB,OAAM,IAAIC,eAAAA,mBAAmB;AAE/B,SAAO,KAAK;;;;;;;;;;;;;CAcd,aAA4D;AAC1D,MAAI,KAAK,OACP,QAAO,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC,GAAG,KAAK,OAAO,CAAC;AAE3C,SAAO,CAAC,GAAG,KAAK,OAAO;;CAGzB,cAAuB;AACrB,SAAO,KAAK,OAAO,WAAW"}
@@ -1,10 +1,12 @@
1
1
  import { BaseChannel } from "./base.cjs";
2
2
 
3
3
  //#region src/channels/topic.d.ts
4
+ /** JS Topic checkpoint when `unique` is set: `[seen, values]`. */
5
+ type UniqueTopicCheckpoint<Value> = [Value[], Value[]];
4
6
  /**
5
7
  * A configurable PubSub Topic.
6
8
  */
7
- declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], [Value[], Value[]]> {
9
+ declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], Value[] | UniqueTopicCheckpoint<Value>> {
8
10
  lc_graph_name: string;
9
11
  unique: boolean;
10
12
  accumulate: boolean;
@@ -20,10 +22,21 @@ declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], [V
20
22
  */
21
23
  accumulate?: boolean;
22
24
  });
23
- fromCheckpoint(checkpoint?: [Value[], Value[]]): this;
25
+ fromCheckpoint(checkpoint?: Value[] | UniqueTopicCheckpoint<Value>): this;
24
26
  update(values: Array<Value | Value[]>): boolean;
25
27
  get(): Array<Value>;
26
- checkpoint(): [Value[], Value[]];
28
+ /**
29
+ * Checkpoint Topic state.
30
+ *
31
+ * Default / Host path (`unique: false`, including `__pregel_tasks`): flat
32
+ * values list, matching Python Topic. Previously this always returned
33
+ * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python
34
+ * checkpointer rejected it.
35
+ *
36
+ * When `unique: true`, keep `[seen, values]` so dedupe history that outlives
37
+ * the current buffer still survives resume.
38
+ */
39
+ checkpoint(): Value[] | UniqueTopicCheckpoint<Value>;
27
40
  isAvailable(): boolean;
28
41
  }
29
42
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"topic.d.cts","names":[],"sources":["../../src/channels/topic.ts"],"mappings":";;;;;AAMA;cAAa,KAAA,gBAAqB,WAAA,CAChC,KAAA,CAAM,KAAA,GACN,KAAA,GAAQ,KAAA,KACP,KAAA,IAAS,KAAA;EAEV,aAAA;EAEA,MAAA;EAEA,UAAA;EAEA,IAAA,EAAM,GAAA,CAAI,KAAA;EAEV,MAAA,EAAQ,KAAA;EAER,WAAA,CAAY,MAAA;IAFJ;;;IAMN,MAAA;IA4BkC;;;IAxBlC,UAAA;EAAA;EAWK,cAAA,CAAe,UAAA,IAAc,KAAA,IAAS,KAAA;EAatC,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,KAAA,GAAQ,KAAA;EAwB7B,GAAA,CAAA,GAAO,KAAA,CAAM,KAAA;EAOb,UAAA,CAAA,IAAe,KAAA,IAAS,KAAA;EAI/B,WAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"topic.d.cts","names":[],"sources":["../../src/channels/topic.ts"],"mappings":";;;;KAIK,qBAAA,WAAgC,KAAA,IAAS,KAAA;AAHN;;;AAAA,cAyB3B,KAAA,gBAAqB,WAAA,CAChC,KAAA,CAAM,KAAA,GACN,KAAA,GAAQ,KAAA,IACR,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAEhC,aAAA;EAEA,MAAA;EAEA,UAAA;EAEA,IAAA,EAAM,GAAA,CAAI,KAAA;EAEV,MAAA,EAAQ,KAAA;EAER,WAAA,CAAY,MAAA;IAfI;;;IAmBd,MAAA;IAjBF;;;IAqBE,UAAA;EAAA;EAWK,cAAA,CAAe,UAAA,GAAa,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAuB5D,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,KAAA,GAAQ,KAAA;EAwB7B,GAAA,CAAA,GAAO,KAAA,CAAM,KAAA;EA/Ce;;;;;;;;;;;EAiE5B,UAAA,CAAA,GAAc,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAOrD,WAAA,CAAA;AAAA"}
@@ -1,10 +1,12 @@
1
1
  import { BaseChannel } from "./base.js";
2
2
 
3
3
  //#region src/channels/topic.d.ts
4
+ /** JS Topic checkpoint when `unique` is set: `[seen, values]`. */
5
+ type UniqueTopicCheckpoint<Value> = [Value[], Value[]];
4
6
  /**
5
7
  * A configurable PubSub Topic.
6
8
  */
7
- declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], [Value[], Value[]]> {
9
+ declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], Value[] | UniqueTopicCheckpoint<Value>> {
8
10
  lc_graph_name: string;
9
11
  unique: boolean;
10
12
  accumulate: boolean;
@@ -20,10 +22,21 @@ declare class Topic<Value> extends BaseChannel<Array<Value>, Value | Value[], [V
20
22
  */
21
23
  accumulate?: boolean;
22
24
  });
23
- fromCheckpoint(checkpoint?: [Value[], Value[]]): this;
25
+ fromCheckpoint(checkpoint?: Value[] | UniqueTopicCheckpoint<Value>): this;
24
26
  update(values: Array<Value | Value[]>): boolean;
25
27
  get(): Array<Value>;
26
- checkpoint(): [Value[], Value[]];
28
+ /**
29
+ * Checkpoint Topic state.
30
+ *
31
+ * Default / Host path (`unique: false`, including `__pregel_tasks`): flat
32
+ * values list, matching Python Topic. Previously this always returned
33
+ * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python
34
+ * checkpointer rejected it.
35
+ *
36
+ * When `unique: true`, keep `[seen, values]` so dedupe history that outlives
37
+ * the current buffer still survives resume.
38
+ */
39
+ checkpoint(): Value[] | UniqueTopicCheckpoint<Value>;
27
40
  isAvailable(): boolean;
28
41
  }
29
42
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"topic.d.ts","names":[],"sources":["../../src/channels/topic.ts"],"mappings":";;;;;AAMA;cAAa,KAAA,gBAAqB,WAAA,CAChC,KAAA,CAAM,KAAA,GACN,KAAA,GAAQ,KAAA,KACP,KAAA,IAAS,KAAA;EAEV,aAAA;EAEA,MAAA;EAEA,UAAA;EAEA,IAAA,EAAM,GAAA,CAAI,KAAA;EAEV,MAAA,EAAQ,KAAA;EAER,WAAA,CAAY,MAAA;IAFJ;;;IAMN,MAAA;IA4BkC;;;IAxBlC,UAAA;EAAA;EAWK,cAAA,CAAe,UAAA,IAAc,KAAA,IAAS,KAAA;EAatC,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,KAAA,GAAQ,KAAA;EAwB7B,GAAA,CAAA,GAAO,KAAA,CAAM,KAAA;EAOb,UAAA,CAAA,IAAe,KAAA,IAAS,KAAA;EAI/B,WAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"topic.d.ts","names":[],"sources":["../../src/channels/topic.ts"],"mappings":";;;;KAIK,qBAAA,WAAgC,KAAA,IAAS,KAAA;AAHN;;;AAAA,cAyB3B,KAAA,gBAAqB,WAAA,CAChC,KAAA,CAAM,KAAA,GACN,KAAA,GAAQ,KAAA,IACR,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAEhC,aAAA;EAEA,MAAA;EAEA,UAAA;EAEA,IAAA,EAAM,GAAA,CAAI,KAAA;EAEV,MAAA,EAAQ,KAAA;EAER,WAAA,CAAY,MAAA;IAfI;;;IAmBd,MAAA;IAjBF;;;IAqBE,UAAA;EAAA;EAWK,cAAA,CAAe,UAAA,GAAa,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAuB5D,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,KAAA,GAAQ,KAAA;EAwB7B,GAAA,CAAA,GAAO,KAAA,CAAM,KAAA;EA/Ce;;;;;;;;;;;EAiE5B,UAAA,CAAA,GAAc,KAAA,KAAU,qBAAA,CAAsB,KAAA;EAOrD,WAAA,CAAA;AAAA"}
@@ -2,6 +2,15 @@ import { EmptyChannelError } from "../errors.js";
2
2
  import { BaseChannel } from "./base.js";
3
3
  //#region src/channels/topic.ts
4
4
  /**
5
+ * Detect the `[seen, values]` Topic checkpoint shape.
6
+ *
7
+ * Used for `unique: true` topics (current) and pre-flat JS checkpoints
8
+ * (legacy). Flat Python-parity checkpoints are a single values list.
9
+ */
10
+ function isUniqueTopicCheckpoint(checkpoint) {
11
+ return Array.isArray(checkpoint) && checkpoint.length === 2 && Array.isArray(checkpoint[0]) && Array.isArray(checkpoint[1]);
12
+ }
13
+ /**
5
14
  * A configurable PubSub Topic.
6
15
  */
7
16
  var Topic = class Topic extends BaseChannel {
@@ -22,10 +31,14 @@ var Topic = class Topic extends BaseChannel {
22
31
  unique: this.unique,
23
32
  accumulate: this.accumulate
24
33
  });
25
- if (typeof checkpoint !== "undefined") {
34
+ if (typeof checkpoint === "undefined") return empty;
35
+ if (isUniqueTopicCheckpoint(checkpoint)) {
26
36
  empty.seen = new Set(checkpoint[0]);
27
- empty.values = checkpoint[1];
37
+ empty.values = [...checkpoint[1]];
38
+ return empty;
28
39
  }
40
+ empty.values = [...checkpoint];
41
+ if (this.unique) empty.seen = new Set(empty.values);
29
42
  return empty;
30
43
  }
31
44
  update(values) {
@@ -51,8 +64,20 @@ var Topic = class Topic extends BaseChannel {
51
64
  if (this.values.length === 0) throw new EmptyChannelError();
52
65
  return this.values;
53
66
  }
67
+ /**
68
+ * Checkpoint Topic state.
69
+ *
70
+ * Default / Host path (`unique: false`, including `__pregel_tasks`): flat
71
+ * values list, matching Python Topic. Previously this always returned
72
+ * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python
73
+ * checkpointer rejected it.
74
+ *
75
+ * When `unique: true`, keep `[seen, values]` so dedupe history that outlives
76
+ * the current buffer still survives resume.
77
+ */
54
78
  checkpoint() {
55
- return [[...this.seen], this.values];
79
+ if (this.unique) return [[...this.seen], [...this.values]];
80
+ return [...this.values];
56
81
  }
57
82
  isAvailable() {
58
83
  return this.values.length !== 0;
@@ -1 +1 @@
1
- {"version":3,"file":"topic.js","names":[],"sources":["../../src/channels/topic.ts"],"sourcesContent":["import { EmptyChannelError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\n/**\n * A configurable PubSub Topic.\n */\nexport class Topic<Value> extends BaseChannel<\n Array<Value>,\n Value | Value[],\n [Value[], Value[]]\n> {\n lc_graph_name = \"Topic\";\n\n unique = false;\n\n accumulate = false;\n\n seen: Set<Value>;\n\n values: Value[];\n\n constructor(fields?: {\n /**\n * Whether to only add unique values to the topic. If `true`, only unique values (using reference equality) will be added to the topic.\n */\n unique?: boolean;\n /**\n * Whether to accumulate values across steps. If `false`, the channel will be emptied after each step.\n */\n accumulate?: boolean;\n }) {\n super();\n\n this.unique = fields?.unique ?? this.unique;\n this.accumulate = fields?.accumulate ?? this.accumulate;\n // State\n this.seen = new Set<Value>();\n this.values = [];\n }\n\n public fromCheckpoint(checkpoint?: [Value[], Value[]]) {\n const empty = new Topic<Value>({\n unique: this.unique,\n accumulate: this.accumulate,\n });\n if (typeof checkpoint !== \"undefined\") {\n empty.seen = new Set(checkpoint[0]);\n // eslint-disable-next-line prefer-destructuring\n empty.values = checkpoint[1];\n }\n return empty as this;\n }\n\n public update(values: Array<Value | Value[]>): boolean {\n let updated = false;\n if (!this.accumulate) {\n updated = this.values.length > 0;\n this.values = [];\n }\n const flatValues = values.flat() as Value[];\n if (flatValues.length > 0) {\n if (this.unique) {\n for (const value of flatValues) {\n if (!this.seen.has(value)) {\n updated = true;\n this.seen.add(value);\n this.values.push(value);\n }\n }\n } else {\n updated = true;\n this.values.push(...flatValues);\n }\n }\n return updated;\n }\n\n public get(): Array<Value> {\n if (this.values.length === 0) {\n throw new EmptyChannelError();\n }\n return this.values;\n }\n\n public checkpoint(): [Value[], Value[]] {\n return [[...this.seen], this.values];\n }\n\n isAvailable(): boolean {\n return this.values.length !== 0;\n }\n}\n"],"mappings":";;;;;;AAMA,IAAa,QAAb,MAAa,cAAqB,YAIhC;CACA,gBAAgB;CAEhB,SAAS;CAET,aAAa;CAEb;CAEA;CAEA,YAAY,QAST;AACD,SAAO;AAEP,OAAK,SAAS,QAAQ,UAAU,KAAK;AACrC,OAAK,aAAa,QAAQ,cAAc,KAAK;AAE7C,OAAK,uBAAO,IAAI,KAAY;AAC5B,OAAK,SAAS,EAAE;;CAGlB,eAAsB,YAAiC;EACrD,MAAM,QAAQ,IAAI,MAAa;GAC7B,QAAQ,KAAK;GACb,YAAY,KAAK;GAClB,CAAC;AACF,MAAI,OAAO,eAAe,aAAa;AACrC,SAAM,OAAO,IAAI,IAAI,WAAW,GAAG;AAEnC,SAAM,SAAS,WAAW;;AAE5B,SAAO;;CAGT,OAAc,QAAyC;EACrD,IAAI,UAAU;AACd,MAAI,CAAC,KAAK,YAAY;AACpB,aAAU,KAAK,OAAO,SAAS;AAC/B,QAAK,SAAS,EAAE;;EAElB,MAAM,aAAa,OAAO,MAAM;AAChC,MAAI,WAAW,SAAS,EACtB,KAAI,KAAK;QACF,MAAM,SAAS,WAClB,KAAI,CAAC,KAAK,KAAK,IAAI,MAAM,EAAE;AACzB,cAAU;AACV,SAAK,KAAK,IAAI,MAAM;AACpB,SAAK,OAAO,KAAK,MAAM;;SAGtB;AACL,aAAU;AACV,QAAK,OAAO,KAAK,GAAG,WAAW;;AAGnC,SAAO;;CAGT,MAA2B;AACzB,MAAI,KAAK,OAAO,WAAW,EACzB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;CAGd,aAAwC;AACtC,SAAO,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,OAAO;;CAGtC,cAAuB;AACrB,SAAO,KAAK,OAAO,WAAW"}
1
+ {"version":3,"file":"topic.js","names":[],"sources":["../../src/channels/topic.ts"],"sourcesContent":["import { EmptyChannelError } from \"../errors.js\";\nimport { BaseChannel } from \"./base.js\";\n\n/** JS Topic checkpoint when `unique` is set: `[seen, values]`. */\ntype UniqueTopicCheckpoint<Value> = [Value[], Value[]];\n\n/**\n * Detect the `[seen, values]` Topic checkpoint shape.\n *\n * Used for `unique: true` topics (current) and pre-flat JS checkpoints\n * (legacy). Flat Python-parity checkpoints are a single values list.\n */\nfunction isUniqueTopicCheckpoint<Value>(\n checkpoint: unknown\n): checkpoint is UniqueTopicCheckpoint<Value> {\n return (\n Array.isArray(checkpoint) &&\n checkpoint.length === 2 &&\n Array.isArray(checkpoint[0]) &&\n Array.isArray(checkpoint[1])\n );\n}\n\n/**\n * A configurable PubSub Topic.\n */\nexport class Topic<Value> extends BaseChannel<\n Array<Value>,\n Value | Value[],\n Value[] | UniqueTopicCheckpoint<Value>\n> {\n lc_graph_name = \"Topic\";\n\n unique = false;\n\n accumulate = false;\n\n seen: Set<Value>;\n\n values: Value[];\n\n constructor(fields?: {\n /**\n * Whether to only add unique values to the topic. If `true`, only unique values (using reference equality) will be added to the topic.\n */\n unique?: boolean;\n /**\n * Whether to accumulate values across steps. If `false`, the channel will be emptied after each step.\n */\n accumulate?: boolean;\n }) {\n super();\n\n this.unique = fields?.unique ?? this.unique;\n this.accumulate = fields?.accumulate ?? this.accumulate;\n // State\n this.seen = new Set<Value>();\n this.values = [];\n }\n\n public fromCheckpoint(checkpoint?: Value[] | UniqueTopicCheckpoint<Value>) {\n const empty = new Topic<Value>({\n unique: this.unique,\n accumulate: this.accumulate,\n });\n if (typeof checkpoint === \"undefined\") {\n return empty as this;\n }\n // `unique: true` (and legacy pre-flat) checkpoints are `[seen, values]`.\n if (isUniqueTopicCheckpoint<Value>(checkpoint)) {\n empty.seen = new Set(checkpoint[0]);\n empty.values = [...checkpoint[1]];\n return empty as this;\n }\n empty.values = [...checkpoint];\n // Flat checkpoints have no historical `seen`. Seed from the current\n // buffer so `unique: true` still de-dupes values present after restore.\n if (this.unique) {\n empty.seen = new Set(empty.values);\n }\n return empty as this;\n }\n\n public update(values: Array<Value | Value[]>): boolean {\n let updated = false;\n if (!this.accumulate) {\n updated = this.values.length > 0;\n this.values = [];\n }\n const flatValues = values.flat() as Value[];\n if (flatValues.length > 0) {\n if (this.unique) {\n for (const value of flatValues) {\n if (!this.seen.has(value)) {\n updated = true;\n this.seen.add(value);\n this.values.push(value);\n }\n }\n } else {\n updated = true;\n this.values.push(...flatValues);\n }\n }\n return updated;\n }\n\n public get(): Array<Value> {\n if (this.values.length === 0) {\n throw new EmptyChannelError();\n }\n return this.values;\n }\n\n /**\n * Checkpoint Topic state.\n *\n * Default / Host path (`unique: false`, including `__pregel_tasks`): flat\n * values list, matching Python Topic. Previously this always returned\n * `[seen, values]`, so empty TASKS became `[[], []]` and Host's Python\n * checkpointer rejected it.\n *\n * When `unique: true`, keep `[seen, values]` so dedupe history that outlives\n * the current buffer still survives resume.\n */\n public checkpoint(): Value[] | UniqueTopicCheckpoint<Value> {\n if (this.unique) {\n return [[...this.seen], [...this.values]];\n }\n return [...this.values];\n }\n\n isAvailable(): boolean {\n return this.values.length !== 0;\n }\n}\n"],"mappings":";;;;;;;;;AAYA,SAAS,wBACP,YAC4C;AAC5C,QACE,MAAM,QAAQ,WAAW,IACzB,WAAW,WAAW,KACtB,MAAM,QAAQ,WAAW,GAAG,IAC5B,MAAM,QAAQ,WAAW,GAAG;;;;;AAOhC,IAAa,QAAb,MAAa,cAAqB,YAIhC;CACA,gBAAgB;CAEhB,SAAS;CAET,aAAa;CAEb;CAEA;CAEA,YAAY,QAST;AACD,SAAO;AAEP,OAAK,SAAS,QAAQ,UAAU,KAAK;AACrC,OAAK,aAAa,QAAQ,cAAc,KAAK;AAE7C,OAAK,uBAAO,IAAI,KAAY;AAC5B,OAAK,SAAS,EAAE;;CAGlB,eAAsB,YAAqD;EACzE,MAAM,QAAQ,IAAI,MAAa;GAC7B,QAAQ,KAAK;GACb,YAAY,KAAK;GAClB,CAAC;AACF,MAAI,OAAO,eAAe,YACxB,QAAO;AAGT,MAAI,wBAA+B,WAAW,EAAE;AAC9C,SAAM,OAAO,IAAI,IAAI,WAAW,GAAG;AACnC,SAAM,SAAS,CAAC,GAAG,WAAW,GAAG;AACjC,UAAO;;AAET,QAAM,SAAS,CAAC,GAAG,WAAW;AAG9B,MAAI,KAAK,OACP,OAAM,OAAO,IAAI,IAAI,MAAM,OAAO;AAEpC,SAAO;;CAGT,OAAc,QAAyC;EACrD,IAAI,UAAU;AACd,MAAI,CAAC,KAAK,YAAY;AACpB,aAAU,KAAK,OAAO,SAAS;AAC/B,QAAK,SAAS,EAAE;;EAElB,MAAM,aAAa,OAAO,MAAM;AAChC,MAAI,WAAW,SAAS,EACtB,KAAI,KAAK;QACF,MAAM,SAAS,WAClB,KAAI,CAAC,KAAK,KAAK,IAAI,MAAM,EAAE;AACzB,cAAU;AACV,SAAK,KAAK,IAAI,MAAM;AACpB,SAAK,OAAO,KAAK,MAAM;;SAGtB;AACL,aAAU;AACV,QAAK,OAAO,KAAK,GAAG,WAAW;;AAGnC,SAAO;;CAGT,MAA2B;AACzB,MAAI,KAAK,OAAO,WAAW,EACzB,OAAM,IAAI,mBAAmB;AAE/B,SAAO,KAAK;;;;;;;;;;;;;CAcd,aAA4D;AAC1D,MAAI,KAAK,OACP,QAAO,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC,GAAG,KAAK,OAAO,CAAC;AAE3C,SAAO,CAAC,GAAG,KAAK,OAAO;;CAGzB,cAAuB;AACrB,SAAO,KAAK,OAAO,WAAW"}
@@ -1269,8 +1269,13 @@ function _excludeAsMetadata(key, value) {
1269
1269
  function _getTracingMetadataDefaults(config) {
1270
1270
  const configurable = config.configurable;
1271
1271
  if (!configurable) return;
1272
+ const context = config.context;
1272
1273
  const metadata = {};
1273
1274
  for (const [key, value] of Object.entries(configurable)) {
1275
+ if (context != null && Object.prototype.hasOwnProperty.call(context, key) && Object.is(context[key], value)) {
1276
+ if (!key.startsWith("__")) metadata[key] = void 0;
1277
+ continue;
1278
+ }
1274
1279
  if (_excludeAsMetadata(key, value)) continue;
1275
1280
  metadata[key] = value;
1276
1281
  }