@langchain/langgraph-api 0.0.39 → 0.0.41

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/api/meta.mjs CHANGED
@@ -1,5 +1,17 @@
1
1
  import { Hono } from "hono";
2
+ import * as fs from "node:fs/promises";
3
+ import * as url from "node:url";
2
4
  const api = new Hono();
5
+ // Get the version using the same pattern as semver/index.mts
6
+ const packageJsonPath = url.fileURLToPath(new URL("../../package.json", import.meta.url));
7
+ let version;
8
+ try {
9
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
10
+ version = packageJson.version;
11
+ }
12
+ catch {
13
+ console.warn("Could not determine version of langgraph-api");
14
+ }
3
15
  // read env variable
4
16
  const env = process.env;
5
17
  api.get("/info", (c) => {
@@ -19,7 +31,14 @@ api.get("/info", (c) => {
19
31
  return undefined;
20
32
  })();
21
33
  return c.json({
22
- flags: { assistants: true, crons: false, langsmith: !!langsmithTracing },
34
+ version,
35
+ context: "js",
36
+ flags: {
37
+ assistants: true,
38
+ crons: false,
39
+ langsmith: !!langsmithTracing,
40
+ langsmith_tracing_replicas: true,
41
+ },
23
42
  });
24
43
  });
25
44
  api.get("/ok", (c) => c.json({ ok: true }));
package/dist/api/runs.mjs CHANGED
@@ -1,19 +1,19 @@
1
+ import { zValidator } from "@hono/zod-validator";
1
2
  import { Hono } from "hono";
2
3
  import { HTTPException } from "hono/http-exception";
3
4
  import { streamSSE } from "hono/streaming";
5
+ import { v4 as uuid4 } from "uuid";
6
+ import { z } from "zod";
4
7
  import { getAssistantId } from "../graph/load.mjs";
5
- import { zValidator } from "@hono/zod-validator";
8
+ import { logError, logger } from "../logging.mjs";
6
9
  import * as schemas from "../schemas.mjs";
7
- import { z } from "zod";
8
10
  import { Runs, Threads } from "../storage/ops.mjs";
9
- import { serialiseAsDict } from "../utils/serde.mjs";
10
11
  import { getDisconnectAbortSignal, jsonExtra, waitKeepAlive, } from "../utils/hono.mjs";
11
- import { logError, logger } from "../logging.mjs";
12
- import { v4 as uuid4 } from "uuid";
12
+ import { serialiseAsDict } from "../utils/serde.mjs";
13
13
  const api = new Hono();
14
14
  const createValidRun = async (threadId, payload, kwargs) => {
15
15
  const { assistant_id: assistantId, ...run } = payload;
16
- const { auth, headers } = kwargs;
16
+ const { auth, headers } = kwargs ?? {};
17
17
  const runId = uuid4();
18
18
  const streamMode = Array.isArray(payload.stream_mode)
19
19
  ? payload.stream_mode
@@ -33,6 +33,13 @@ const createValidRun = async (threadId, payload, kwargs) => {
33
33
  config.configurable ??= {};
34
34
  Object.assign(config.configurable, run.checkpoint);
35
35
  }
36
+ if (run.langsmith_tracer) {
37
+ config.configurable ??= {};
38
+ Object.assign(config.configurable, {
39
+ langsmith_project: run.langsmith_tracer.project_name,
40
+ langsmith_example_id: run.langsmith_tracer.example_id,
41
+ });
42
+ }
36
43
  if (headers) {
37
44
  for (const [rawKey, value] of headers.entries()) {
38
45
  const key = rawKey.toLowerCase();
@@ -111,18 +111,7 @@ api.get("/threads/:thread_id/history", zValidator("param", z.object({ thread_id:
111
111
  const states = await Threads.State.list({ configurable: { thread_id, checkpoint_ns: "" } }, { limit, before }, c.var.auth);
112
112
  return jsonExtra(c, states.map(stateSnapshotToThreadState));
113
113
  });
114
- api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", z.object({
115
- limit: z.number().optional().default(10),
116
- before: z.string().optional(),
117
- metadata: z.record(z.string(), z.unknown()).optional(),
118
- checkpoint: z
119
- .object({
120
- checkpoint_id: z.string().uuid().optional(),
121
- checkpoint_ns: z.string().optional(),
122
- checkpoint_map: z.record(z.string(), z.unknown()).optional(),
123
- })
124
- .optional(),
125
- })), async (c) => {
114
+ api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
126
115
  // Get Thread History Post
127
116
  const { thread_id } = c.req.valid("param");
128
117
  const { limit, before, metadata, checkpoint } = c.req.valid("json");
@@ -140,7 +129,7 @@ api.delete("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.st
140
129
  await Threads.delete(thread_id, c.var.auth);
141
130
  return new Response(null, { status: 204 });
142
131
  });
143
- api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", z.object({ metadata: z.record(z.string(), z.unknown()) })), async (c) => {
132
+ api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadPatchRequest), async (c) => {
144
133
  // Patch Thread
145
134
  const { thread_id } = c.req.valid("param");
146
135
  const { metadata } = c.req.valid("json");
@@ -0,0 +1,26 @@
1
+ import type { BaseCheckpointSaver, BaseStore, Pregel } from "@langchain/langgraph";
2
+ import { Hono } from "hono";
3
+ import type { Metadata } from "../storage/ops.mjs";
4
+ type AnyPregel = Pregel<any, any, any, any, any>;
5
+ interface Thread {
6
+ thread_id: string;
7
+ metadata: Metadata;
8
+ }
9
+ interface ThreadSaver {
10
+ get: (id: string) => Promise<Thread>;
11
+ put: (id: string, options: {
12
+ metadata?: Metadata;
13
+ }) => Promise<void>;
14
+ delete: (id: string) => Promise<void>;
15
+ }
16
+ /**
17
+ * Attach LangGraph Platform-esque routes to a given Hono instance.
18
+ * @experimental Does not follow semver.
19
+ */
20
+ export declare function createEmbedServer(options: {
21
+ graph: Record<string, AnyPregel>;
22
+ threads: ThreadSaver;
23
+ checkpointer: BaseCheckpointSaver;
24
+ store?: BaseStore;
25
+ }): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
26
+ export {};
@@ -0,0 +1,167 @@
1
+ import { Hono } from "hono";
2
+ import { zValidator } from "@hono/zod-validator";
3
+ import { streamSSE } from "hono/streaming";
4
+ import { v4 as uuidv4 } from "uuid";
5
+ import * as schemas from "../schemas.mjs";
6
+ import { z } from "zod";
7
+ import { streamState } from "../stream.mjs";
8
+ import { serialiseAsDict } from "../utils/serde.mjs";
9
+ import { getDisconnectAbortSignal, jsonExtra } from "../utils/hono.mjs";
10
+ import { stateSnapshotToThreadState } from "../state.mjs";
11
+ import { ensureContentType } from "../http/middleware.mjs";
12
+ function createStubRun(threadId, payload) {
13
+ const now = new Date();
14
+ const runId = uuidv4();
15
+ const streamMode = Array.isArray(payload.stream_mode)
16
+ ? payload.stream_mode
17
+ : payload.stream_mode
18
+ ? [payload.stream_mode]
19
+ : undefined;
20
+ const config = Object.assign({}, payload.config ?? {}, {
21
+ configurable: {
22
+ run_id: runId,
23
+ thread_id: threadId,
24
+ graph_id: payload.assistant_id,
25
+ },
26
+ }, { metadata: payload.metadata ?? {} });
27
+ return {
28
+ run_id: runId,
29
+ thread_id: threadId,
30
+ assistant_id: payload.assistant_id,
31
+ metadata: payload.metadata ?? {},
32
+ status: "running",
33
+ kwargs: {
34
+ input: payload.input,
35
+ command: payload.command,
36
+ config,
37
+ stream_mode: streamMode,
38
+ interrupt_before: payload.interrupt_before,
39
+ interrupt_after: payload.interrupt_after,
40
+ feedback_keys: payload.feedback_keys,
41
+ subgraphs: payload.stream_subgraphs,
42
+ temporary: false,
43
+ },
44
+ multitask_strategy: "reject",
45
+ created_at: now,
46
+ updated_at: now,
47
+ };
48
+ }
49
+ /**
50
+ * Attach LangGraph Platform-esque routes to a given Hono instance.
51
+ * @experimental Does not follow semver.
52
+ */
53
+ export function createEmbedServer(options) {
54
+ async function getGraph(graphId) {
55
+ const targetGraph = options.graph[graphId];
56
+ targetGraph.store = options.store;
57
+ targetGraph.checkpointer = options.checkpointer;
58
+ return targetGraph;
59
+ }
60
+ const api = new Hono();
61
+ api.use(ensureContentType());
62
+ api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
63
+ // create a new threaad
64
+ const payload = c.req.valid("json");
65
+ const threadId = payload.thread_id || uuidv4();
66
+ await options.threads.put(threadId, payload);
67
+ return jsonExtra(c, { thread_id: threadId });
68
+ });
69
+ api.get("/threads/:thread_id/state", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("query", z.object({ subgraphs: schemas.coercedBoolean.optional() })), async (c) => {
70
+ // Get Latest Thread State
71
+ const { thread_id } = c.req.valid("param");
72
+ const { subgraphs } = c.req.valid("query");
73
+ const thread = await options.threads.get(thread_id);
74
+ const graphId = thread.metadata?.graph_id;
75
+ const graph = graphId ? options.graph[graphId] : undefined;
76
+ if (graph == null) {
77
+ return jsonExtra(c, stateSnapshotToThreadState({
78
+ values: {},
79
+ next: [],
80
+ config: {},
81
+ metadata: undefined,
82
+ createdAt: undefined,
83
+ parentConfig: undefined,
84
+ tasks: [],
85
+ }));
86
+ }
87
+ const config = { configurable: { thread_id } };
88
+ const result = await graph.getState(config, { subgraphs });
89
+ return jsonExtra(c, stateSnapshotToThreadState(result));
90
+ });
91
+ api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
92
+ // Get Thread History Post
93
+ const { thread_id } = c.req.valid("param");
94
+ const { limit, before, metadata, checkpoint } = c.req.valid("json");
95
+ const thread = await options.threads.get(thread_id);
96
+ const graphId = thread.metadata?.graph_id;
97
+ const graph = graphId ? options.graph[graphId] : undefined;
98
+ if (graph == null)
99
+ return jsonExtra(c, []);
100
+ const config = { configurable: { thread_id, ...checkpoint } };
101
+ const result = [];
102
+ const beforeConfig = typeof before === "string"
103
+ ? { configurable: { checkpoint_id: before } }
104
+ : before;
105
+ for await (const state of graph.getStateHistory(config, {
106
+ limit,
107
+ before: beforeConfig,
108
+ filter: metadata,
109
+ })) {
110
+ result.push(stateSnapshotToThreadState(state));
111
+ }
112
+ return jsonExtra(c, result);
113
+ });
114
+ api.post("/threads/:thread_id/runs/stream", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
115
+ // Stream Run
116
+ return streamSSE(c, async (stream) => {
117
+ const { thread_id } = c.req.valid("param");
118
+ const payload = c.req.valid("json");
119
+ const signal = getDisconnectAbortSignal(c, stream);
120
+ const run = createStubRun(thread_id, payload);
121
+ // update thread with new graph_id
122
+ const thread = await options.threads.get(thread_id);
123
+ await options.threads.put(thread_id, {
124
+ metadata: {
125
+ ...thread.metadata,
126
+ graph_id: payload.assistant_id,
127
+ assistant_id: payload.assistant_id,
128
+ },
129
+ });
130
+ for await (const { event, data } of streamState(run, {
131
+ attempt: 1,
132
+ getGraph,
133
+ signal,
134
+ })) {
135
+ await stream.writeSSE({ data: serialiseAsDict(data), event });
136
+ }
137
+ });
138
+ });
139
+ api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
140
+ // Stream Stateless Run
141
+ return streamSSE(c, async (stream) => {
142
+ const payload = c.req.valid("json");
143
+ const signal = getDisconnectAbortSignal(c, stream);
144
+ const threadId = uuidv4();
145
+ await options.threads.put(threadId, {
146
+ metadata: {
147
+ graph_id: payload.assistant_id,
148
+ assistant_id: payload.assistant_id,
149
+ },
150
+ });
151
+ try {
152
+ const run = createStubRun(threadId, payload);
153
+ for await (const { event, data } of streamState(run, {
154
+ attempt: 1,
155
+ getGraph,
156
+ signal,
157
+ })) {
158
+ await stream.writeSSE({ data: serialiseAsDict(data), event });
159
+ }
160
+ }
161
+ finally {
162
+ await options.threads.delete(threadId);
163
+ }
164
+ });
165
+ });
166
+ return api;
167
+ }
package/dist/queue.mjs CHANGED
@@ -3,6 +3,7 @@ import { streamState, } from "./stream.mjs";
3
3
  import { logError, logger } from "./logging.mjs";
4
4
  import { serializeError } from "./utils/serde.mjs";
5
5
  import { callWebhook } from "./webhook.mjs";
6
+ import { getGraph } from "./graph/load.mjs";
6
7
  const MAX_RETRY_ATTEMPTS = 3;
7
8
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8
9
  export const queue = async () => {
@@ -14,7 +15,7 @@ export const queue = async () => {
14
15
  await sleep(1000 * Math.random());
15
16
  }
16
17
  };
17
- const worker = async (run, attempt, abortSignal) => {
18
+ const worker = async (run, attempt, signal) => {
18
19
  const startedAt = new Date();
19
20
  let endedAt = undefined;
20
21
  let checkpoint = undefined;
@@ -48,8 +49,10 @@ const worker = async (run, attempt, abortSignal) => {
48
49
  const runId = run.run_id;
49
50
  const resumable = run.kwargs?.resumable ?? false;
50
51
  try {
51
- const stream = streamState(run, attempt, {
52
- signal: abortSignal,
52
+ const stream = streamState(run, {
53
+ getGraph,
54
+ attempt,
55
+ signal,
53
56
  ...(!temporary ? { onCheckpoint, onTaskResult } : undefined),
54
57
  });
55
58
  for await (const { event, data } of stream) {
@@ -579,6 +579,16 @@ export declare const CommandSchema: z.ZodObject<{
579
579
  })[] | undefined;
580
580
  resume?: unknown;
581
581
  }>;
582
+ export declare const LangsmithTracer: z.ZodObject<{
583
+ project_name: z.ZodOptional<z.ZodString>;
584
+ example_id: z.ZodOptional<z.ZodString>;
585
+ }, "strip", z.ZodTypeAny, {
586
+ project_name?: string | undefined;
587
+ example_id?: string | undefined;
588
+ }, {
589
+ project_name?: string | undefined;
590
+ example_id?: string | undefined;
591
+ }>;
582
592
  export declare const RunCreate: z.ZodObject<{
583
593
  assistant_id: z.ZodUnion<[z.ZodString, z.ZodString]>;
584
594
  checkpoint_id: z.ZodOptional<z.ZodString>;
@@ -692,6 +702,16 @@ export declare const RunCreate: z.ZodObject<{
692
702
  if_not_exists: z.ZodOptional<z.ZodEnum<["reject", "create"]>>;
693
703
  on_completion: z.ZodOptional<z.ZodEnum<["delete", "keep"]>>;
694
704
  feedback_keys: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
705
+ langsmith_tracer: z.ZodOptional<z.ZodObject<{
706
+ project_name: z.ZodOptional<z.ZodString>;
707
+ example_id: z.ZodOptional<z.ZodString>;
708
+ }, "strip", z.ZodTypeAny, {
709
+ project_name?: string | undefined;
710
+ example_id?: string | undefined;
711
+ }, {
712
+ project_name?: string | undefined;
713
+ example_id?: string | undefined;
714
+ }>>;
695
715
  }, "strip", z.ZodTypeAny, {
696
716
  assistant_id: string;
697
717
  on_disconnect: "cancel" | "continue";
@@ -739,6 +759,10 @@ export declare const RunCreate: z.ZodObject<{
739
759
  stream_subgraphs?: boolean | undefined;
740
760
  stream_resumable?: boolean | undefined;
741
761
  on_completion?: "delete" | "keep" | undefined;
762
+ langsmith_tracer?: {
763
+ project_name?: string | undefined;
764
+ example_id?: string | undefined;
765
+ } | undefined;
742
766
  }, {
743
767
  assistant_id: string;
744
768
  metadata?: z.objectInputType<{}, z.ZodAny, "strip"> | undefined;
@@ -786,6 +810,10 @@ export declare const RunCreate: z.ZodObject<{
786
810
  stream_subgraphs?: boolean | undefined;
787
811
  stream_resumable?: boolean | undefined;
788
812
  on_completion?: "delete" | "keep" | undefined;
813
+ langsmith_tracer?: {
814
+ project_name?: string | undefined;
815
+ example_id?: string | undefined;
816
+ } | undefined;
789
817
  }>;
790
818
  export declare const RunBatchCreate: z.ZodArray<z.ZodObject<{
791
819
  assistant_id: z.ZodUnion<[z.ZodString, z.ZodString]>;
@@ -900,6 +928,16 @@ export declare const RunBatchCreate: z.ZodArray<z.ZodObject<{
900
928
  if_not_exists: z.ZodOptional<z.ZodEnum<["reject", "create"]>>;
901
929
  on_completion: z.ZodOptional<z.ZodEnum<["delete", "keep"]>>;
902
930
  feedback_keys: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
931
+ langsmith_tracer: z.ZodOptional<z.ZodObject<{
932
+ project_name: z.ZodOptional<z.ZodString>;
933
+ example_id: z.ZodOptional<z.ZodString>;
934
+ }, "strip", z.ZodTypeAny, {
935
+ project_name?: string | undefined;
936
+ example_id?: string | undefined;
937
+ }, {
938
+ project_name?: string | undefined;
939
+ example_id?: string | undefined;
940
+ }>>;
903
941
  }, "strip", z.ZodTypeAny, {
904
942
  assistant_id: string;
905
943
  on_disconnect: "cancel" | "continue";
@@ -947,6 +985,10 @@ export declare const RunBatchCreate: z.ZodArray<z.ZodObject<{
947
985
  stream_subgraphs?: boolean | undefined;
948
986
  stream_resumable?: boolean | undefined;
949
987
  on_completion?: "delete" | "keep" | undefined;
988
+ langsmith_tracer?: {
989
+ project_name?: string | undefined;
990
+ example_id?: string | undefined;
991
+ } | undefined;
950
992
  }, {
951
993
  assistant_id: string;
952
994
  metadata?: z.objectInputType<{}, z.ZodAny, "strip"> | undefined;
@@ -994,6 +1036,10 @@ export declare const RunBatchCreate: z.ZodArray<z.ZodObject<{
994
1036
  stream_subgraphs?: boolean | undefined;
995
1037
  stream_resumable?: boolean | undefined;
996
1038
  on_completion?: "delete" | "keep" | undefined;
1039
+ langsmith_tracer?: {
1040
+ project_name?: string | undefined;
1041
+ example_id?: string | undefined;
1042
+ } | undefined;
997
1043
  }>, "many">;
998
1044
  export declare const SearchResult: z.ZodObject<{
999
1045
  metadata: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>>;
@@ -1294,6 +1340,49 @@ export declare const ThreadStateUpdate: z.ZodObject<{
1294
1340
  checkpoint_id?: string | undefined;
1295
1341
  as_node?: string | undefined;
1296
1342
  }>;
1343
+ export declare const ThreadHistoryRequest: z.ZodObject<{
1344
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
1345
+ before: z.ZodOptional<z.ZodString>;
1346
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1347
+ checkpoint: z.ZodOptional<z.ZodObject<{
1348
+ checkpoint_id: z.ZodOptional<z.ZodString>;
1349
+ checkpoint_ns: z.ZodOptional<z.ZodString>;
1350
+ checkpoint_map: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1351
+ }, "strip", z.ZodTypeAny, {
1352
+ checkpoint_ns?: string | undefined;
1353
+ checkpoint_id?: string | undefined;
1354
+ checkpoint_map?: Record<string, unknown> | undefined;
1355
+ }, {
1356
+ checkpoint_ns?: string | undefined;
1357
+ checkpoint_id?: string | undefined;
1358
+ checkpoint_map?: Record<string, unknown> | undefined;
1359
+ }>>;
1360
+ }, "strip", z.ZodTypeAny, {
1361
+ limit: number;
1362
+ metadata?: Record<string, unknown> | undefined;
1363
+ checkpoint?: {
1364
+ checkpoint_ns?: string | undefined;
1365
+ checkpoint_id?: string | undefined;
1366
+ checkpoint_map?: Record<string, unknown> | undefined;
1367
+ } | undefined;
1368
+ before?: string | undefined;
1369
+ }, {
1370
+ metadata?: Record<string, unknown> | undefined;
1371
+ checkpoint?: {
1372
+ checkpoint_ns?: string | undefined;
1373
+ checkpoint_id?: string | undefined;
1374
+ checkpoint_map?: Record<string, unknown> | undefined;
1375
+ } | undefined;
1376
+ limit?: number | undefined;
1377
+ before?: string | undefined;
1378
+ }>;
1379
+ export declare const ThreadPatchRequest: z.ZodObject<{
1380
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1381
+ }, "strip", z.ZodTypeAny, {
1382
+ metadata: Record<string, unknown>;
1383
+ }, {
1384
+ metadata: Record<string, unknown>;
1385
+ }>;
1297
1386
  export declare const AssistantLatestVersion: z.ZodObject<{
1298
1387
  version: z.ZodNumber;
1299
1388
  }, "strip", z.ZodTypeAny, {
package/dist/schemas.mjs CHANGED
@@ -159,6 +159,10 @@ export const CommandSchema = z.object({
159
159
  .optional(),
160
160
  resume: z.unknown().optional(),
161
161
  });
162
+ export const LangsmithTracer = z.object({
163
+ project_name: z.string().optional(),
164
+ example_id: z.string().optional(),
165
+ });
162
166
  export const RunCreate = z
163
167
  .object({
164
168
  assistant_id: z.union([z.string().uuid(), z.string()]),
@@ -210,6 +214,7 @@ export const RunCreate = z
210
214
  if_not_exists: z.enum(["reject", "create"]).optional(),
211
215
  on_completion: z.enum(["delete", "keep"]).optional(),
212
216
  feedback_keys: z.array(z.string()).optional(),
217
+ langsmith_tracer: LangsmithTracer.optional(),
213
218
  })
214
219
  .describe("Payload for creating a stateful run.");
215
220
  export const RunBatchCreate = z
@@ -383,6 +388,21 @@ export const ThreadStateUpdate = z
383
388
  as_node: z.string().optional(),
384
389
  })
385
390
  .describe("Payload for adding state to a thread.");
391
+ export const ThreadHistoryRequest = z.object({
392
+ limit: z.number().optional().default(10),
393
+ before: z.string().optional(),
394
+ metadata: z.record(z.string(), z.unknown()).optional(),
395
+ checkpoint: z
396
+ .object({
397
+ checkpoint_id: z.string().uuid().optional(),
398
+ checkpoint_ns: z.string().optional(),
399
+ checkpoint_map: z.record(z.string(), z.unknown()).optional(),
400
+ })
401
+ .optional(),
402
+ });
403
+ export const ThreadPatchRequest = z.object({
404
+ metadata: z.record(z.string(), z.unknown()),
405
+ });
386
406
  export const AssistantLatestVersion = z.object({
387
407
  version: z.number(),
388
408
  });
@@ -744,27 +744,37 @@ export class Runs {
744
744
  static async *next() {
745
745
  yield* conn.withGenerator(async function* (STORE, options) {
746
746
  const now = new Date();
747
- const pendingRuns = Object.values(STORE.runs)
747
+ const pendingRunIds = Object.values(STORE.runs)
748
748
  .filter((run) => run.status === "pending" && run.created_at < now)
749
- .sort((a, b) => a.created_at.getTime() - b.created_at.getTime());
750
- if (!pendingRuns.length) {
749
+ .sort((a, b) => a.created_at.getTime() - b.created_at.getTime())
750
+ .map((run) => run.run_id);
751
+ if (!pendingRunIds.length) {
751
752
  return;
752
753
  }
753
- for (const run of pendingRuns) {
754
- const runId = run.run_id;
755
- const threadId = run.thread_id;
756
- const thread = STORE.threads[threadId];
757
- if (!thread) {
758
- await console.warn(`Unexpected missing thread in Runs.next: ${threadId}`);
759
- continue;
760
- }
754
+ for (const runId of pendingRunIds) {
761
755
  if (StreamManager.isLocked(runId))
762
756
  continue;
763
757
  try {
764
758
  const signal = StreamManager.lock(runId);
759
+ const run = STORE.runs[runId];
760
+ if (!run)
761
+ continue;
762
+ const threadId = run.thread_id;
763
+ const thread = STORE.threads[threadId];
764
+ if (!thread) {
765
+ logger.warn(`Unexpected missing thread in Runs.next: ${threadId}`);
766
+ continue;
767
+ }
768
+ // is the run still valid?
769
+ if (run.status !== "pending")
770
+ continue;
771
+ if (Object.values(STORE.runs).some((run) => run.thread_id === threadId && run.status === "running")) {
772
+ continue;
773
+ }
765
774
  options.schedulePersist();
766
775
  STORE.retry_counter[runId] ??= 0;
767
776
  STORE.retry_counter[runId] += 1;
777
+ STORE.runs[runId].status = "running";
768
778
  yield { run, attempt: STORE.retry_counter[runId], signal };
769
779
  }
770
780
  finally {
@@ -842,7 +852,8 @@ export class Runs {
842
852
  }
843
853
  // if multitask_mode = reject, check for inflight runs
844
854
  // and if there are any, return them to reject putting a new run
845
- const inflightRuns = Object.values(STORE.runs).filter((run) => run.thread_id === threadId && run.status === "pending");
855
+ const inflightRuns = Object.values(STORE.runs).filter((run) => run.thread_id === threadId &&
856
+ (run.status === "pending" || run.status === "running"));
846
857
  if (options?.preventInsertInInflight) {
847
858
  if (inflightRuns.length > 0)
848
859
  return inflightRuns;
@@ -1090,7 +1101,7 @@ export class Runs {
1090
1101
  yield { event: "error", data: "Run not found" };
1091
1102
  break;
1092
1103
  }
1093
- else if (run.status !== "pending") {
1104
+ else if (run.status !== "pending" && run.status !== "running") {
1094
1105
  break;
1095
1106
  }
1096
1107
  }
package/dist/stream.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import type { Run, RunnableConfig, Checkpoint } from "./storage/ops.mjs";
2
- import { type CheckpointMetadata, type Interrupt, type StateSnapshot } from "@langchain/langgraph";
1
+ import type { BaseCheckpointSaver, LangGraphRunnableConfig, CheckpointMetadata, Interrupt, StateSnapshot } from "@langchain/langgraph";
2
+ import type { Pregel } from "@langchain/langgraph/pregel";
3
+ import type { Checkpoint, Run, RunnableConfig } from "./storage/ops.mjs";
3
4
  interface DebugTask {
4
5
  id: string;
5
6
  name: string;
@@ -27,7 +28,11 @@ export type StreamTaskResult = Prettify<Omit<DebugTask, "state"> & {
27
28
  state?: StateSnapshot;
28
29
  checkpoint?: Checkpoint;
29
30
  }>;
30
- export declare function streamState(run: Run, attempt?: number, options?: {
31
+ export declare function streamState(run: Run, options: {
32
+ attempt: number;
33
+ getGraph: (graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
34
+ checkpointer?: BaseCheckpointSaver | null;
35
+ }) => Promise<Pregel<any, any, any, any, any>>;
31
36
  onCheckpoint?: (checkpoint: StreamCheckpoint) => void;
32
37
  onTaskResult?: (taskResult: StreamTaskResult) => void;
33
38
  signal?: AbortSignal;
package/dist/stream.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { getGraph } from "./graph/load.mjs";
2
- import { Client as LangSmithClient } from "langsmith";
3
- import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
4
1
  import { isBaseMessage } from "@langchain/core/messages";
2
+ import { LangChainTracer } from "@langchain/core/tracers/tracer_langchain";
3
+ import { Client as LangSmithClient, getDefaultProjectName } from "langsmith";
5
4
  import { getLangGraphCommand } from "./command.mjs";
6
5
  import { checkLangGraphSemver } from "./semver/index.mjs";
6
+ import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
7
7
  const isRunnableConfig = (config) => {
8
8
  if (typeof config !== "object" || config == null)
9
9
  return false;
@@ -53,13 +53,13 @@ function preprocessDebugCheckpoint(payload) {
53
53
  return result;
54
54
  }
55
55
  let LANGGRAPH_VERSION;
56
- export async function* streamState(run, attempt = 1, options) {
56
+ export async function* streamState(run, options) {
57
57
  const kwargs = run.kwargs;
58
58
  const graphId = kwargs.config?.configurable?.graph_id;
59
59
  if (!graphId || typeof graphId !== "string") {
60
60
  throw new Error("Invalid or missing graph_id");
61
61
  }
62
- const graph = await getGraph(graphId, kwargs.config, {
62
+ const graph = await options.getGraph(graphId, kwargs.config, {
63
63
  checkpointer: kwargs.temporary ? null : undefined,
64
64
  });
65
65
  const userStreamMode = kwargs.stream_mode ?? [];
@@ -74,7 +74,7 @@ export async function* streamState(run, attempt = 1, options) {
74
74
  libStreamMode.add("debug");
75
75
  yield {
76
76
  event: "metadata",
77
- data: { run_id: run.run_id, attempt },
77
+ data: { run_id: run.run_id, attempt: options.attempt },
78
78
  };
79
79
  if (!LANGGRAPH_VERSION) {
80
80
  const version = await checkLangGraphSemver();
@@ -82,12 +82,25 @@ export async function* streamState(run, attempt = 1, options) {
82
82
  }
83
83
  const metadata = {
84
84
  ...kwargs.config?.metadata,
85
- run_attempt: attempt,
85
+ run_attempt: options.attempt,
86
86
  langgraph_version: LANGGRAPH_VERSION?.version ?? "0.0.0",
87
87
  langgraph_plan: "developer",
88
88
  langgraph_host: "self-hosted",
89
89
  langgraph_api_url: process.env.LANGGRAPH_API_URL ?? undefined,
90
90
  };
91
+ const tracer = run.kwargs?.config?.configurable?.langsmith_project
92
+ ? new LangChainTracer({
93
+ replicas: [
94
+ [
95
+ run.kwargs?.config?.configurable?.langsmith_project,
96
+ {
97
+ reference_example_id: run.kwargs?.config?.configurable?.langsmith_example_id,
98
+ },
99
+ ],
100
+ [getDefaultProjectName(), undefined],
101
+ ],
102
+ })
103
+ : undefined;
91
104
  const events = graph.streamEvents(kwargs.command != null
92
105
  ? getLangGraphCommand(kwargs.command)
93
106
  : (kwargs.input ?? null), {
@@ -102,6 +115,7 @@ export async function* streamState(run, attempt = 1, options) {
102
115
  runId: run.run_id,
103
116
  streamMode: [...libStreamMode],
104
117
  signal: options?.signal,
118
+ ...(tracer && { callbacks: [tracer] }),
105
119
  });
106
120
  const messages = {};
107
121
  const completedIds = new Set();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-api",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"
@@ -27,6 +27,10 @@
27
27
  "types": "./dist/graph/parser/index.d.mts",
28
28
  "default": "./dist/graph/parser/index.mjs"
29
29
  },
30
+ "./experimental/embed": {
31
+ "types": "./dist/experimental/embed.d.mts",
32
+ "default": "./dist/experimental/embed.mjs"
33
+ },
30
34
  "./package.json": "./package.json"
31
35
  },
32
36
  "repository": {
@@ -49,14 +53,14 @@
49
53
  "@babel/code-frame": "^7.26.2",
50
54
  "@hono/node-server": "^1.12.0",
51
55
  "@hono/zod-validator": "^0.2.2",
52
- "@langchain/langgraph-ui": "0.0.39",
56
+ "@langchain/langgraph-ui": "0.0.41",
53
57
  "@types/json-schema": "^7.0.15",
54
58
  "@typescript/vfs": "^1.6.0",
55
59
  "dedent": "^1.5.3",
56
60
  "dotenv": "^16.4.7",
57
61
  "exit-hook": "^4.0.0",
58
62
  "hono": "^4.5.4",
59
- "langsmith": "^0.2.15",
63
+ "langsmith": "^0.3.33",
60
64
  "open": "^10.1.0",
61
65
  "semver": "^7.7.1",
62
66
  "stacktrace-parser": "^0.1.10",
@@ -68,7 +72,7 @@
68
72
  "zod": "^3.23.8"
69
73
  },
70
74
  "peerDependencies": {
71
- "@langchain/core": "^0.3.42",
75
+ "@langchain/core": "^0.3.59",
72
76
  "@langchain/langgraph": "^0.2.57 || ^0.3.0",
73
77
  "@langchain/langgraph-checkpoint": "~0.0.16",
74
78
  "@langchain/langgraph-sdk": "~0.0.70",
@@ -80,7 +84,7 @@
80
84
  }
81
85
  },
82
86
  "devDependencies": {
83
- "@langchain/core": "^0.3.42",
87
+ "@langchain/core": "^0.3.59",
84
88
  "@langchain/langgraph": "^0.2.57",
85
89
  "@langchain/langgraph-checkpoint": "~0.0.16",
86
90
  "@langchain/langgraph-sdk": "^0.0.77",