@langchain/langgraph-checkpoint 0.0.2 → 0.0.4

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.
package/dist/base.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
3
+ exports.maxChannelVersion = exports.compareChannelVersions = exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
4
4
  const id_js_1 = require("./id.cjs");
5
5
  const jsonplus_js_1 = require("./serde/jsonplus.cjs");
6
6
  function deepCopy(obj) {
@@ -63,7 +63,25 @@ class BaseCheckpointSaver {
63
63
  * as long as they are monotonically increasing.
64
64
  */
65
65
  getNextVersion(current, _channel) {
66
- return current !== undefined ? current + 1 : 1;
66
+ if (typeof current === "string") {
67
+ throw new Error("Please override this method to use string versions.");
68
+ }
69
+ return (current !== undefined && typeof current === "number" ? current + 1 : 1);
67
70
  }
68
71
  }
69
72
  exports.BaseCheckpointSaver = BaseCheckpointSaver;
73
+ function compareChannelVersions(a, b) {
74
+ if (typeof a === "number" && typeof b === "number") {
75
+ return Math.sign(a - b);
76
+ }
77
+ return String(a).localeCompare(String(b));
78
+ }
79
+ exports.compareChannelVersions = compareChannelVersions;
80
+ function maxChannelVersion(...versions) {
81
+ return versions.reduce((max, version, idx) => {
82
+ if (idx === 0)
83
+ return version;
84
+ return compareChannelVersions(max, version) >= 0 ? max : version;
85
+ });
86
+ }
87
+ exports.maxChannelVersion = maxChannelVersion;
package/dist/base.d.ts CHANGED
@@ -2,7 +2,8 @@ import type { RunnableConfig } from "@langchain/core/runnables";
2
2
  import { SerializerProtocol } from "./serde/base.js";
3
3
  import type { PendingWrite, CheckpointPendingWrite, CheckpointMetadata } from "./types.js";
4
4
  import type { ChannelProtocol, SendProtocol } from "./serde/types.js";
5
- export type ChannelVersions = Record<string, string | number>;
5
+ type ChannelVersion = number | string;
6
+ export type ChannelVersions = Record<string, ChannelVersion>;
6
7
  export interface Checkpoint<N extends string = string, C extends string = string> {
7
8
  /**
8
9
  * Version number
@@ -23,11 +24,11 @@ export interface Checkpoint<N extends string = string, C extends string = string
23
24
  /**
24
25
  * @default {}
25
26
  */
26
- channel_versions: Record<C, number>;
27
+ channel_versions: Record<C, ChannelVersion>;
27
28
  /**
28
29
  * @default {}
29
30
  */
30
- versions_seen: Record<N, Record<C, number>>;
31
+ versions_seen: Record<N, Record<C, ChannelVersion>>;
31
32
  /**
32
33
  * List of packets sent to nodes but not yet processed.
33
34
  * Cleared by the next checkpoint.
@@ -36,8 +37,8 @@ export interface Checkpoint<N extends string = string, C extends string = string
36
37
  }
37
38
  export interface ReadonlyCheckpoint extends Readonly<Checkpoint> {
38
39
  readonly channel_values: Readonly<Record<string, unknown>>;
39
- readonly channel_versions: Readonly<Record<string, number>>;
40
- readonly versions_seen: Readonly<Record<string, Readonly<Record<string, number>>>>;
40
+ readonly channel_versions: Readonly<Record<string, ChannelVersion>>;
41
+ readonly versions_seen: Readonly<Record<string, Readonly<Record<string, ChannelVersion>>>>;
41
42
  }
42
43
  export declare function deepCopy<T>(obj: T): T;
43
44
  /** @hidden */
@@ -56,7 +57,7 @@ export type CheckpointListOptions = {
56
57
  before?: RunnableConfig;
57
58
  filter?: Record<string, any>;
58
59
  };
59
- export declare abstract class BaseCheckpointSaver<V = number> {
60
+ export declare abstract class BaseCheckpointSaver<V extends string | number = number> {
60
61
  serde: SerializerProtocol;
61
62
  constructor(serde?: SerializerProtocol);
62
63
  get(config: RunnableConfig): Promise<Checkpoint | undefined>;
@@ -73,5 +74,8 @@ export declare abstract class BaseCheckpointSaver<V = number> {
73
74
  * Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,
74
75
  * as long as they are monotonically increasing.
75
76
  */
76
- getNextVersion(current: V | undefined, _channel: ChannelProtocol): number;
77
+ getNextVersion(current: V | undefined, _channel: ChannelProtocol): V;
77
78
  }
79
+ export declare function compareChannelVersions(a: ChannelVersion, b: ChannelVersion): number;
80
+ export declare function maxChannelVersion(...versions: ChannelVersion[]): ChannelVersion;
81
+ export {};
package/dist/base.js CHANGED
@@ -57,6 +57,22 @@ export class BaseCheckpointSaver {
57
57
  * as long as they are monotonically increasing.
58
58
  */
59
59
  getNextVersion(current, _channel) {
60
- return current !== undefined ? current + 1 : 1;
60
+ if (typeof current === "string") {
61
+ throw new Error("Please override this method to use string versions.");
62
+ }
63
+ return (current !== undefined && typeof current === "number" ? current + 1 : 1);
64
+ }
65
+ }
66
+ export function compareChannelVersions(a, b) {
67
+ if (typeof a === "number" && typeof b === "number") {
68
+ return Math.sign(a - b);
61
69
  }
70
+ return String(a).localeCompare(String(b));
71
+ }
72
+ export function maxChannelVersion(...versions) {
73
+ return versions.reduce((max, version, idx) => {
74
+ if (idx === 0)
75
+ return version;
76
+ return compareChannelVersions(max, version) >= 0 ? max : version;
77
+ });
62
78
  }
@@ -4,6 +4,52 @@ exports.JsonPlusSerializer = void 0;
4
4
  /* eslint-disable @typescript-eslint/no-explicit-any */
5
5
  /* eslint-disable no-instanceof/no-instanceof */
6
6
  const load_1 = require("@langchain/core/load");
7
+ function isLangChainSerializable(value) {
8
+ return (typeof value.lc_serializable === "boolean" && Array.isArray(value.lc_id));
9
+ }
10
+ function isLangChainSerializedObject(value) {
11
+ return (value !== null &&
12
+ value.lc === 1 &&
13
+ value.type === "constructor" &&
14
+ Array.isArray(value.id));
15
+ }
16
+ const _serialize = (value, seen = new WeakSet()) => {
17
+ const defaultValue = _default("", value);
18
+ if (defaultValue === null) {
19
+ return "null";
20
+ }
21
+ else if (typeof defaultValue === "string") {
22
+ return JSON.stringify(defaultValue);
23
+ }
24
+ else if (typeof defaultValue === "number" ||
25
+ typeof defaultValue === "boolean") {
26
+ return defaultValue.toString();
27
+ }
28
+ else if (typeof defaultValue === "object") {
29
+ if (seen.has(defaultValue)) {
30
+ throw new TypeError("Circular reference detected");
31
+ }
32
+ seen.add(defaultValue);
33
+ if (Array.isArray(defaultValue)) {
34
+ const result = `[${defaultValue
35
+ .map((item) => _serialize(item, seen))
36
+ .join(",")}]`;
37
+ seen.delete(defaultValue);
38
+ return result;
39
+ }
40
+ else if (isLangChainSerializable(defaultValue)) {
41
+ return JSON.stringify(defaultValue);
42
+ }
43
+ else {
44
+ const entries = Object.entries(defaultValue).map(([k, v]) => `${JSON.stringify(k)}:${_serialize(v, seen)}`);
45
+ const result = `{${entries.join(",")}}`;
46
+ seen.delete(defaultValue);
47
+ return result;
48
+ }
49
+ }
50
+ // Only be reached for functions or symbols
51
+ return JSON.stringify(defaultValue);
52
+ };
7
53
  async function _reviver(value) {
8
54
  if (value && typeof value === "object") {
9
55
  if (value.lc === 2 && value.type === "undefined") {
@@ -42,7 +88,7 @@ async function _reviver(value) {
42
88
  return value;
43
89
  }
44
90
  }
45
- else if (value.lc === 1) {
91
+ else if (isLangChainSerializedObject(value)) {
46
92
  return (0, load_1.load)(JSON.stringify(value));
47
93
  }
48
94
  else if (Array.isArray(value)) {
@@ -94,24 +140,8 @@ function _default(_key, obj) {
94
140
  }
95
141
  class JsonPlusSerializer {
96
142
  _dumps(obj) {
97
- const jsonString = JSON.stringify(obj, (key, value) => {
98
- if (value && typeof value === "object") {
99
- if (Array.isArray(value)) {
100
- // Handle arrays
101
- return value.map((item) => _default(key, item));
102
- }
103
- else {
104
- // Handle objects
105
- const serialized = {};
106
- for (const [k, v] of Object.entries(value)) {
107
- serialized[k] = _default(k, v);
108
- }
109
- return serialized;
110
- }
111
- }
112
- return _default(key, value);
113
- });
114
- return new TextEncoder().encode(jsonString);
143
+ const encoder = new TextEncoder();
144
+ return encoder.encode(_serialize(obj));
115
145
  }
116
146
  dumpsTyped(obj) {
117
147
  if (obj instanceof Uint8Array) {
@@ -1,6 +1,52 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable no-instanceof/no-instanceof */
3
3
  import { load } from "@langchain/core/load";
4
+ function isLangChainSerializable(value) {
5
+ return (typeof value.lc_serializable === "boolean" && Array.isArray(value.lc_id));
6
+ }
7
+ function isLangChainSerializedObject(value) {
8
+ return (value !== null &&
9
+ value.lc === 1 &&
10
+ value.type === "constructor" &&
11
+ Array.isArray(value.id));
12
+ }
13
+ const _serialize = (value, seen = new WeakSet()) => {
14
+ const defaultValue = _default("", value);
15
+ if (defaultValue === null) {
16
+ return "null";
17
+ }
18
+ else if (typeof defaultValue === "string") {
19
+ return JSON.stringify(defaultValue);
20
+ }
21
+ else if (typeof defaultValue === "number" ||
22
+ typeof defaultValue === "boolean") {
23
+ return defaultValue.toString();
24
+ }
25
+ else if (typeof defaultValue === "object") {
26
+ if (seen.has(defaultValue)) {
27
+ throw new TypeError("Circular reference detected");
28
+ }
29
+ seen.add(defaultValue);
30
+ if (Array.isArray(defaultValue)) {
31
+ const result = `[${defaultValue
32
+ .map((item) => _serialize(item, seen))
33
+ .join(",")}]`;
34
+ seen.delete(defaultValue);
35
+ return result;
36
+ }
37
+ else if (isLangChainSerializable(defaultValue)) {
38
+ return JSON.stringify(defaultValue);
39
+ }
40
+ else {
41
+ const entries = Object.entries(defaultValue).map(([k, v]) => `${JSON.stringify(k)}:${_serialize(v, seen)}`);
42
+ const result = `{${entries.join(",")}}`;
43
+ seen.delete(defaultValue);
44
+ return result;
45
+ }
46
+ }
47
+ // Only be reached for functions or symbols
48
+ return JSON.stringify(defaultValue);
49
+ };
4
50
  async function _reviver(value) {
5
51
  if (value && typeof value === "object") {
6
52
  if (value.lc === 2 && value.type === "undefined") {
@@ -39,7 +85,7 @@ async function _reviver(value) {
39
85
  return value;
40
86
  }
41
87
  }
42
- else if (value.lc === 1) {
88
+ else if (isLangChainSerializedObject(value)) {
43
89
  return load(JSON.stringify(value));
44
90
  }
45
91
  else if (Array.isArray(value)) {
@@ -91,24 +137,8 @@ function _default(_key, obj) {
91
137
  }
92
138
  export class JsonPlusSerializer {
93
139
  _dumps(obj) {
94
- const jsonString = JSON.stringify(obj, (key, value) => {
95
- if (value && typeof value === "object") {
96
- if (Array.isArray(value)) {
97
- // Handle arrays
98
- return value.map((item) => _default(key, item));
99
- }
100
- else {
101
- // Handle objects
102
- const serialized = {};
103
- for (const [k, v] of Object.entries(value)) {
104
- serialized[k] = _default(k, v);
105
- }
106
- return serialized;
107
- }
108
- }
109
- return _default(key, value);
110
- });
111
- return new TextEncoder().encode(jsonString);
140
+ const encoder = new TextEncoder();
141
+ return encoder.encode(_serialize(obj));
112
142
  }
113
143
  dumpsTyped(obj) {
114
144
  if (obj instanceof Uint8Array) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-checkpoint",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Library with base interfaces for LangGraph checkpoint savers.",
5
5
  "type": "module",
6
6
  "engines": {