@langchain/langgraph-api 0.0.17 → 0.0.18

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.
@@ -15,6 +15,9 @@ api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
15
15
  metadata: payload.metadata,
16
16
  if_exists: payload.if_exists ?? "raise",
17
17
  });
18
+ if (payload.supersteps?.length) {
19
+ await Threads.State.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps);
20
+ }
18
21
  return jsonExtra(c, thread);
19
22
  });
20
23
  api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), async (c) => {
@@ -37,5 +37,5 @@ logger.info(`Server running at ${host}`);
37
37
  let queryParams = `?baseUrl=http://${options.host}:${options.port}`;
38
38
  if (organizationId)
39
39
  queryParams += `&organizationId=${organizationId}`;
40
- asyncExitHook(cleanup, { wait: 1000 });
40
+ asyncExitHook(cleanup, { wait: 3_000 });
41
41
  sendToParent?.({ queryParams });
@@ -0,0 +1,15 @@
1
+ import { Command, Send } from "@langchain/langgraph";
2
+ export const getLangGraphCommand = (command) => {
3
+ let goto = command.goto != null && !Array.isArray(command.goto)
4
+ ? [command.goto]
5
+ : command.goto;
6
+ return new Command({
7
+ goto: goto?.map((item) => {
8
+ if (typeof item !== "string")
9
+ return new Send(item.node, item.input);
10
+ return item;
11
+ }),
12
+ update: command.update,
13
+ resume: command.resume,
14
+ });
15
+ };
package/dist/schemas.mjs CHANGED
@@ -140,35 +140,31 @@ export const Run = z.object({
140
140
  kwargs: z.object({}).catchall(z.any()),
141
141
  multitask_strategy: z.enum(["reject", "rollback", "interrupt", "enqueue"]),
142
142
  });
143
+ export const CommandSchema = z.object({
144
+ goto: z
145
+ .union([
146
+ z.union([
147
+ z.string(),
148
+ z.object({ node: z.string(), input: z.unknown().optional() }),
149
+ ]),
150
+ z.array(z.union([
151
+ z.string(),
152
+ z.object({ node: z.string(), input: z.unknown().optional() }),
153
+ ])),
154
+ ])
155
+ .optional(),
156
+ update: z
157
+ .union([z.record(z.unknown()), z.array(z.tuple([z.string(), z.unknown()]))])
158
+ .optional(),
159
+ resume: z.unknown().optional(),
160
+ });
143
161
  export const RunCreate = z
144
162
  .object({
145
163
  assistant_id: z.union([z.string().uuid(), z.string()]),
146
164
  checkpoint_id: z.string().optional(),
147
165
  checkpoint: CheckpointSchema.optional(),
148
166
  input: z.union([z.unknown(), z.null()]).optional(),
149
- command: z
150
- .object({
151
- goto: z
152
- .union([
153
- z.union([
154
- z.string(),
155
- z.object({ node: z.string(), input: z.unknown().optional() }),
156
- ]),
157
- z.array(z.union([
158
- z.string(),
159
- z.object({ node: z.string(), input: z.unknown().optional() }),
160
- ])),
161
- ])
162
- .optional(),
163
- update: z
164
- .union([
165
- z.record(z.unknown()),
166
- z.array(z.tuple([z.string(), z.unknown()])),
167
- ])
168
- .optional(),
169
- resume: z.unknown().optional(),
170
- })
171
- .optional(),
167
+ command: CommandSchema.optional(),
172
168
  metadata: z
173
169
  .object({})
174
170
  .catchall(z.any())
@@ -301,6 +297,16 @@ export const Thread = z.object({
301
297
  });
302
298
  export const ThreadCreate = z
303
299
  .object({
300
+ supersteps: z
301
+ .array(z.object({
302
+ updates: z.array(z.object({
303
+ values: z.unknown().nullish(),
304
+ command: CommandSchema.nullish(),
305
+ as_node: z.string(),
306
+ })),
307
+ }))
308
+ .describe("The supersteps to apply to the thread.")
309
+ .optional(),
304
310
  thread_id: z
305
311
  .string()
306
312
  .uuid()
@@ -6,6 +6,7 @@ import { store } from "./store.mjs";
6
6
  import { logger } from "../logging.mjs";
7
7
  import { serializeError } from "../utils/serde.mjs";
8
8
  import { FileSystemPersistence } from "./persist.mjs";
9
+ import { getLangGraphCommand } from "../command.mjs";
9
10
  export const conn = new FileSystemPersistence(".langgraphjs_ops.json", () => ({
10
11
  runs: {},
11
12
  threads: {},
@@ -487,6 +488,41 @@ export class Threads {
487
488
  });
488
489
  return { checkpoint: nextConfig.configurable };
489
490
  }
491
+ static async bulk(config, supersteps) {
492
+ const threadId = config.configurable?.thread_id;
493
+ if (!threadId)
494
+ return [];
495
+ const thread = await Threads.get(threadId);
496
+ const graphId = thread.metadata?.graph_id;
497
+ if (graphId == null) {
498
+ throw new HTTPException(400, {
499
+ message: `Thread ${threadId} has no graph ID`,
500
+ });
501
+ }
502
+ config.configurable ??= {};
503
+ config.configurable.graph_id ??= graphId;
504
+ const graph = await getGraph(graphId, { checkpointer, store });
505
+ const updateConfig = structuredClone(config);
506
+ updateConfig.configurable ??= {};
507
+ updateConfig.configurable.checkpoint_ns ??= "";
508
+ const nextConfig = await graph.bulkUpdateState(updateConfig, supersteps.map((i) => ({
509
+ updates: i.updates.map((j) => ({
510
+ values: j.command != null ? getLangGraphCommand(j.command) : j.values,
511
+ asNode: j.as_node,
512
+ })),
513
+ })));
514
+ const state = await Threads.State.get(config, { subgraphs: false });
515
+ // update thread values
516
+ await conn.with(async (STORE) => {
517
+ for (const thread of Object.values(STORE.threads)) {
518
+ if (thread.thread_id === threadId) {
519
+ thread.values = state.values;
520
+ break;
521
+ }
522
+ }
523
+ });
524
+ return { checkpoint: nextConfig.configurable };
525
+ }
490
526
  static async list(config, options) {
491
527
  const threadId = config.configurable?.thread_id;
492
528
  if (!threadId)
@@ -513,7 +549,7 @@ export class Threads {
513
549
  }
514
550
  export class Runs {
515
551
  static async *next() {
516
- yield* conn.withGenerator(async function* (STORE) {
552
+ yield* conn.withGenerator(async function* (STORE, options) {
517
553
  const now = new Date();
518
554
  const pendingRuns = Object.values(STORE.runs)
519
555
  .filter((run) => run.status === "pending" && run.created_at < now)
@@ -533,6 +569,7 @@ export class Runs {
533
569
  continue;
534
570
  try {
535
571
  const signal = StreamManager.lock(runId);
572
+ options.schedulePersist();
536
573
  STORE.retry_counter[runId] ??= 0;
537
574
  STORE.retry_counter[runId] += 1;
538
575
  yield { run, attempt: STORE.retry_counter[runId], signal };
@@ -67,12 +67,15 @@ export class FileSystemPersistence {
67
67
  if (this.filepath == null || this.data == null) {
68
68
  throw new Error(`${this.name} not initialized`);
69
69
  }
70
+ let shouldPersist = false;
71
+ let schedulePersist = () => void (shouldPersist = true);
70
72
  try {
71
- const gen = typeof fn === "function" ? fn(this.data) : fn;
73
+ const gen = typeof fn === "function" ? fn(this.data, { schedulePersist }) : fn;
72
74
  yield* gen;
73
75
  }
74
76
  finally {
75
- this.schedulePersist();
77
+ if (shouldPersist)
78
+ this.schedulePersist();
76
79
  }
77
80
  }
78
81
  }
package/dist/stream.mjs CHANGED
@@ -1,22 +1,8 @@
1
1
  import { getGraph } from "./graph/load.mjs";
2
2
  import { Client as LangSmithClient } from "langsmith";
3
- import { Command, Send, } from "@langchain/langgraph";
4
3
  import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
5
4
  import { isBaseMessage } from "@langchain/core/messages";
6
- const getLangGraphCommand = (command) => {
7
- let goto = command.goto != null && !Array.isArray(command.goto)
8
- ? [command.goto]
9
- : command.goto;
10
- return new Command({
11
- goto: goto?.map((item) => {
12
- if (typeof item !== "string")
13
- return new Send(item.node, item.input);
14
- return item;
15
- }),
16
- update: command.update,
17
- resume: command.resume,
18
- });
19
- };
5
+ import { getLangGraphCommand } from "./command.mjs";
20
6
  const isRunnableConfig = (config) => {
21
7
  if (typeof config !== "object" || config == null)
22
8
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-api",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"
@@ -47,13 +47,13 @@
47
47
  "zod": "^3.23.8"
48
48
  },
49
49
  "peerDependencies": {
50
- "@langchain/core": "^0.3.40",
51
- "@langchain/langgraph": "^0.2.49",
52
- "@langchain/langgraph-checkpoint": "^0.0.15",
50
+ "@langchain/core": "^0.3.42",
51
+ "@langchain/langgraph": "^0.2.57",
52
+ "@langchain/langgraph-checkpoint": "^0.0.16",
53
53
  "typescript": "^5.5.4"
54
54
  },
55
55
  "devDependencies": {
56
- "@langchain/langgraph-sdk": "^0.0.33",
56
+ "@langchain/langgraph-sdk": "^0.0.60",
57
57
  "@types/babel__code-frame": "^7.0.6",
58
58
  "@types/react": "^19.0.8",
59
59
  "@types/react-dom": "^19.0.3",