langgraph-api 0.2.9__py3-none-any.whl → 0.2.10__py3-none-any.whl

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.

Potentially problematic release.


This version of langgraph-api might be problematic. Click here for more details.

@@ -1,885 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
-
3
- import { SubgraphExtractor } from "../src/parser/parser.mjs";
4
- import dedent from "dedent";
5
-
6
- // TODO: investigate why Github Actions fails on timeout on these tests
7
- const isParserSkipped = process.env.JS_PARSER_TESTS_SKIPPED === "true";
8
-
9
- describe
10
- .skipIf(isParserSkipped)
11
- .concurrent("graph factories", { timeout: 10_000 }, () => {
12
- const common = dedent`
13
- import { HumanMessage } from "@langchain/core/messages";
14
- import { MessagesAnnotation, StateGraph } from "@langchain/langgraph";
15
-
16
- const builder = new StateGraph(MessagesAnnotation)
17
- .addNode("parent", () => {
18
- return { messages: [new HumanMessage("parent")] };
19
- })
20
- .addNode("child", async (state) => {
21
- return { messages: [new HumanMessage("child")] };
22
- })
23
- .addEdge("__start__", "parent")
24
- .addEdge("parent", "child")
25
- .addEdge("child", "__end__");
26
- `;
27
-
28
- const MessagesSchema = {
29
- type: "object",
30
- properties: {
31
- messages: {
32
- type: "array",
33
- items: { $ref: "#/definitions/BaseMessage" },
34
- },
35
- },
36
- definitions: {
37
- BaseMessage: {
38
- oneOf: expect.arrayContaining([
39
- { $ref: "#/definitions/BaseMessageChunk" },
40
- ]),
41
- },
42
- },
43
- $schema: "http://json-schema.org/draft-07/schema#",
44
- };
45
-
46
- const ConfigSchema = {
47
- type: "object",
48
- $schema: "http://json-schema.org/draft-07/schema#",
49
- };
50
-
51
- test.concurrent.for([
52
- ["builder.compile()"], // CompiledGraph
53
- ["() => builder.compile()"], // () => CompiledGraph
54
- ["builder"], // Graph
55
- ["() => builder"], // () => Graph
56
-
57
- ["(async () => builder)()"], // Promise<CompiledGraph>
58
- ["async () => builder.compile()"], // () => Promise<CompiledGraph>
59
- ["(async () => builder)()"], // Promise<Graph>
60
- ["async () => builder"], // () => Promise<Graph>
61
- ])("%s", { timeout: 10_000 }, ([prop]) => {
62
- const schemas = SubgraphExtractor.extractSchemas(
63
- { contents: `${common}\n\nexport const graph = ${prop};` },
64
- "graph",
65
- );
66
-
67
- expect(schemas.graph.input).toMatchObject(MessagesSchema);
68
- expect(schemas.graph.output).toMatchObject(MessagesSchema);
69
- expect(schemas.graph.state).toMatchObject(MessagesSchema);
70
- expect(schemas.graph.config).toEqual(ConfigSchema);
71
- });
72
- });
73
-
74
- describe
75
- .skipIf(isParserSkipped)
76
- .concurrent("subgraphs", { timeout: 10_000 }, () => {
77
- test.concurrent.for([
78
- ["subgraph"],
79
- ["(state) => subgraph.invoke(state)"],
80
- ["async (state) => await subgraph.invoke(state)"],
81
- ])(`basic: %s`, { timeout: 10_000 }, ([nodeDef]) => {
82
- const schemas = SubgraphExtractor.extractSchemas(
83
- {
84
- contents: dedent`
85
- import { HumanMessage } from "@langchain/core/messages";
86
- import {
87
- Annotation,
88
- MessagesAnnotation,
89
- StateGraph,
90
- } from "@langchain/langgraph";
91
-
92
- const ParentSchema = MessagesAnnotation;
93
-
94
- const SubgraphSchema = Annotation.Root({
95
- ...MessagesAnnotation.spec,
96
- kind: Annotation<"weather" | "other">,
97
- });
98
-
99
- const subgraph = new StateGraph(SubgraphSchema)
100
- .addNode("child", () => {
101
- return { messages: [new HumanMessage("Hello from child")] };
102
- })
103
- .addEdge("__start__", "child")
104
- .compile();
105
-
106
- export const graph = new StateGraph(ParentSchema)
107
- .addNode("parent", () => {
108
- return { messages: [new HumanMessage("Hello from child")] };
109
- })
110
- .addNode("child", ${nodeDef})
111
- .addEdge("__start__", "parent")
112
- .addEdge("parent", "child")
113
- .addEdge("child", "__end__")
114
- .compile();
115
- `,
116
- },
117
- "graph",
118
- );
119
- expect(schemas["graph|child"].input).toMatchObject({
120
- type: "object",
121
- properties: {
122
- kind: {
123
- type: "string",
124
- enum: expect.arrayContaining(["weather", "other"]),
125
- },
126
- messages: {
127
- type: "array",
128
- items: { $ref: "#/definitions/BaseMessage" },
129
- },
130
- },
131
- definitions: {
132
- BaseMessage: {
133
- oneOf: expect.arrayContaining([
134
- { $ref: "#/definitions/BaseMessageChunk" },
135
- ]),
136
- },
137
- },
138
- $schema: "http://json-schema.org/draft-07/schema#",
139
- });
140
-
141
- expect(schemas["graph|child"].output).toMatchObject({
142
- type: "object",
143
- properties: {
144
- kind: {
145
- type: "string",
146
- enum: expect.arrayContaining(["weather", "other"]),
147
- },
148
- messages: {
149
- type: "array",
150
- items: { $ref: "#/definitions/BaseMessage" },
151
- },
152
- },
153
- definitions: {
154
- BaseMessage: {
155
- oneOf: expect.arrayContaining([
156
- { $ref: "#/definitions/BaseMessageChunk" },
157
- ]),
158
- },
159
- },
160
- $schema: "http://json-schema.org/draft-07/schema#",
161
- });
162
-
163
- expect(schemas["graph|child"].state).toMatchObject({
164
- type: "object",
165
- properties: {
166
- kind: {
167
- type: "string",
168
- enum: expect.arrayContaining(["weather", "other"]),
169
- },
170
- messages: {
171
- type: "array",
172
- items: { $ref: "#/definitions/BaseMessage" },
173
- },
174
- },
175
- definitions: {
176
- BaseMessage: {
177
- oneOf: expect.arrayContaining([
178
- { $ref: "#/definitions/BaseMessageChunk" },
179
- ]),
180
- },
181
- },
182
- $schema: "http://json-schema.org/draft-07/schema#",
183
- });
184
-
185
- expect(schemas["graph|child"].config).toMatchObject({
186
- type: "object",
187
- $schema: "http://json-schema.org/draft-07/schema#",
188
- });
189
- });
190
-
191
- test.concurrent("nested subgraphs", { timeout: 10_000 }, () => {
192
- const schemas = SubgraphExtractor.extractSchemas(
193
- {
194
- contents: dedent`
195
- import { HumanMessage } from "@langchain/core/messages";
196
- import {
197
- Annotation,
198
- MessagesAnnotation,
199
- StateGraph,
200
- } from "@langchain/langgraph";
201
-
202
- const ParentSchema = MessagesAnnotation;
203
-
204
- const ChildSchema = Annotation.Root({
205
- ...MessagesAnnotation.spec,
206
- child: Annotation<"alpha" | "beta">,
207
- });
208
-
209
- const SubchildSchema = Annotation.Root({
210
- ...MessagesAnnotation.spec,
211
- subchild: Annotation<"one" | "two">,
212
- });
213
-
214
- const subchild = new StateGraph(SubchildSchema)
215
- .addNode("subchild_one", () => ({ messages: [new HumanMessage("subchild_one")] }))
216
- .addNode("subchild_two", () => ({ messages: [new HumanMessage("subchild_two")] }))
217
- .addEdge("__start__", "subchild_one")
218
- .addEdge("subchild_one", "subchild_two")
219
- .compile();
220
-
221
- const child = new StateGraph(ChildSchema)
222
- .addNode("child_one", () => ({ messages: [new HumanMessage("child_one")] }))
223
- .addNode("child_two", subchild)
224
- .addEdge("__start__", "child_one")
225
- .addEdge("child_one", "child_two")
226
- .compile();
227
-
228
- export const parent = new StateGraph(ParentSchema)
229
- .addNode("parent_one", () => ({ messages: [new HumanMessage("parent_one")] }))
230
- .addNode("parent_two", child)
231
- .addEdge("__start__", "parent_one")
232
- .addEdge("parent_one", "parent_two")
233
- .compile();
234
- `,
235
- },
236
- "parent",
237
- );
238
-
239
- expect(Object.keys(schemas)).toEqual(
240
- expect.arrayContaining([
241
- "parent",
242
- "parent|parent_two",
243
- "parent|parent_two|child_two",
244
- ]),
245
- );
246
-
247
- expect(schemas.parent.state).toMatchObject({
248
- type: "object",
249
- properties: {
250
- messages: {
251
- type: "array",
252
- items: { $ref: "#/definitions/BaseMessage" },
253
- },
254
- },
255
- definitions: {
256
- BaseMessage: {
257
- oneOf: expect.arrayContaining([
258
- { $ref: "#/definitions/BaseMessageChunk" },
259
- ]),
260
- },
261
- },
262
- $schema: "http://json-schema.org/draft-07/schema#",
263
- });
264
-
265
- expect(schemas["parent|parent_two"].state).toMatchObject({
266
- type: "object",
267
- properties: {
268
- child: {
269
- type: "string",
270
- enum: expect.arrayContaining(["alpha", "beta"]),
271
- },
272
- messages: {
273
- type: "array",
274
- items: { $ref: "#/definitions/BaseMessage" },
275
- },
276
- },
277
- definitions: {
278
- BaseMessage: {
279
- oneOf: expect.arrayContaining([
280
- { $ref: "#/definitions/BaseMessageChunk" },
281
- ]),
282
- },
283
- },
284
- $schema: "http://json-schema.org/draft-07/schema#",
285
- });
286
-
287
- expect(schemas["parent|parent_two|child_two"].state).toMatchObject({
288
- type: "object",
289
- properties: {
290
- subchild: {
291
- type: "string",
292
- enum: expect.arrayContaining(["one", "two"]),
293
- },
294
- messages: {
295
- type: "array",
296
- items: { $ref: "#/definitions/BaseMessage" },
297
- },
298
- },
299
- definitions: {
300
- BaseMessage: {
301
- oneOf: expect.arrayContaining([
302
- { $ref: "#/definitions/BaseMessageChunk" },
303
- ]),
304
- },
305
- },
306
- $schema: "http://json-schema.org/draft-07/schema#",
307
- });
308
- });
309
-
310
- test.concurrent(
311
- "multiple subgraphs within a single node",
312
- { timeout: 10_000 },
313
- () => {
314
- expect(() => {
315
- SubgraphExtractor.extractSchemas(
316
- {
317
- contents: dedent`
318
- import { HumanMessage } from "@langchain/core/messages";
319
- import {
320
- Annotation,
321
- MessagesAnnotation,
322
- StateGraph,
323
- } from "@langchain/langgraph";
324
-
325
- const ParentSchema = MessagesAnnotation;
326
-
327
- const ChildSchema = Annotation.Root({
328
- ...MessagesAnnotation.spec,
329
- child: Annotation<"alpha" | "beta">,
330
- });
331
-
332
- const SubchildSchema = Annotation.Root({
333
- ...MessagesAnnotation.spec,
334
- subchild: Annotation<"one" | "two">,
335
- });
336
-
337
- const subchild = new StateGraph(SubchildSchema)
338
- .addNode("subchild_one", () => ({ messages: [new HumanMessage("subchild_one")] }))
339
- .addNode("subchild_two", () => ({ messages: [new HumanMessage("subchild_two")] }))
340
- .addEdge("__start__", "subchild_one")
341
- .addEdge("subchild_one", "subchild_two")
342
- .compile();
343
-
344
- const child = new StateGraph(ChildSchema)
345
- .addNode("child_one", () => ({ messages: [new HumanMessage("child_one")] }))
346
- .addNode("child_two", () => ({ messages: [new HumanMessage("child_two")] }))
347
- .addEdge("__start__", "child_one")
348
- .addEdge("child_one", "child_two")
349
- .compile();
350
-
351
- export const parent = new StateGraph(ParentSchema)
352
- .addNode("parent_one", async (schema) => {
353
- const messages = []
354
- messages.concat((await child.invoke(schema)).messages)
355
- messages.concat((await subchild.invoke(schema)).messages)
356
- return { messages }
357
- })
358
- .addNode("parent_two", child)
359
- .addEdge("__start__", "parent_one")
360
- .addEdge("parent_one", "parent_two")
361
- .compile();
362
- `,
363
- },
364
- "parent",
365
- { strict: true },
366
- );
367
- }).toThrowError(
368
- `Multiple unique subgraph invocations found for "parent|parent_one"`,
369
- );
370
- },
371
- );
372
-
373
- test.concurrent("imported subgraphs", { timeout: 10_000 }, () => {
374
- const schemas = SubgraphExtractor.extractSchemas(
375
- {
376
- contents: dedent`
377
- import { HumanMessage } from "@langchain/core/messages";
378
- import { subgraph } from "./subgraph.mts";
379
- import {
380
- Annotation,
381
- MessagesAnnotation,
382
- StateGraph,
383
- } from "@langchain/langgraph";
384
-
385
- const ParentSchema = MessagesAnnotation;
386
-
387
- const SubgraphSchema = Annotation.Root({
388
- ...MessagesAnnotation.spec,
389
- kind: Annotation<"weather" | "other">,
390
- });
391
-
392
- export const graph = new StateGraph(ParentSchema)
393
- .addNode("parent", () => {
394
- return { messages: [new HumanMessage("Hello from child")] };
395
- })
396
- .addNode("child", subgraph)
397
- .addEdge("__start__", "parent")
398
- .addEdge("parent", "child")
399
- .addEdge("child", "__end__")
400
- .compile();
401
- `,
402
- files: [
403
- [
404
- "./subgraph.mts",
405
- dedent`
406
- import { HumanMessage } from "@langchain/core/messages";
407
- import {
408
- Annotation,
409
- MessagesAnnotation,
410
- StateGraph,
411
- } from "@langchain/langgraph";
412
-
413
- const SubgraphSchema = Annotation.Root({
414
- ...MessagesAnnotation.spec,
415
- kind: Annotation<"weather" | "other">,
416
- });
417
-
418
- export const subgraph = new StateGraph(SubgraphSchema)
419
- .addNode("child", () => {
420
- return { messages: [new HumanMessage("Hello from child")] };
421
- })
422
- .addEdge("__start__", "child")
423
- .compile();
424
- `,
425
- ],
426
- ],
427
- },
428
- "graph",
429
- );
430
-
431
- expect(Object.keys(schemas)).toEqual(
432
- expect.arrayContaining(["graph", "graph|child"]),
433
- );
434
-
435
- expect(schemas["graph|child"].input).toMatchObject({
436
- type: "object",
437
- properties: {
438
- kind: {
439
- type: "string",
440
- enum: expect.arrayContaining(["weather", "other"]),
441
- },
442
- messages: {
443
- type: "array",
444
- items: { $ref: "#/definitions/BaseMessage" },
445
- },
446
- },
447
- definitions: {
448
- BaseMessage: {
449
- oneOf: expect.arrayContaining([
450
- { $ref: "#/definitions/BaseMessageChunk" },
451
- ]),
452
- },
453
- },
454
- $schema: "http://json-schema.org/draft-07/schema#",
455
- });
456
-
457
- expect(schemas["graph|child"].output).toMatchObject({
458
- type: "object",
459
- properties: {
460
- kind: {
461
- type: "string",
462
- enum: expect.arrayContaining(["weather", "other"]),
463
- },
464
- messages: {
465
- type: "array",
466
- items: { $ref: "#/definitions/BaseMessage" },
467
- },
468
- },
469
- definitions: {
470
- BaseMessage: {
471
- oneOf: expect.arrayContaining([
472
- { $ref: "#/definitions/BaseMessageChunk" },
473
- ]),
474
- },
475
- },
476
- $schema: "http://json-schema.org/draft-07/schema#",
477
- });
478
-
479
- expect(schemas["graph|child"].state).toMatchObject({
480
- type: "object",
481
- properties: {
482
- kind: {
483
- type: "string",
484
- enum: expect.arrayContaining(["weather", "other"]),
485
- },
486
- messages: {
487
- type: "array",
488
- items: { $ref: "#/definitions/BaseMessage" },
489
- },
490
- },
491
- definitions: {
492
- BaseMessage: {
493
- oneOf: expect.arrayContaining([
494
- { $ref: "#/definitions/BaseMessageChunk" },
495
- ]),
496
- },
497
- },
498
- $schema: "http://json-schema.org/draft-07/schema#",
499
- });
500
-
501
- expect(schemas["graph|child"].config).toMatchObject({
502
- type: "object",
503
- $schema: "http://json-schema.org/draft-07/schema#",
504
- });
505
- });
506
-
507
- test.concurrent(
508
- "imported uncompiled subgraphs",
509
- { timeout: 10_000 },
510
- () => {
511
- const schemas = SubgraphExtractor.extractSchemas(
512
- {
513
- contents: dedent`
514
- import { HumanMessage } from "@langchain/core/messages";
515
- import { subgraph } from "./subgraph.mts";
516
- import {
517
- Annotation,
518
- MessagesAnnotation,
519
- StateGraph,
520
- } from "@langchain/langgraph";
521
-
522
- const ParentSchema = MessagesAnnotation;
523
-
524
- const SubgraphSchema = Annotation.Root({
525
- ...MessagesAnnotation.spec,
526
- kind: Annotation<"weather" | "other">,
527
- });
528
-
529
- export const graph = new StateGraph(ParentSchema)
530
- .addNode("parent", () => {
531
- return { messages: [new HumanMessage("Hello from child")] };
532
- })
533
- .addNode("child", subgraph.compile())
534
- .addEdge("__start__", "parent")
535
- .addEdge("parent", "child")
536
- .addEdge("child", "__end__")
537
- .compile();
538
- `,
539
- files: [
540
- [
541
- "./subgraph.mts",
542
- dedent`
543
- import { HumanMessage } from "@langchain/core/messages";
544
- import {
545
- Annotation,
546
- MessagesAnnotation,
547
- StateGraph,
548
- } from "@langchain/langgraph";
549
-
550
- const SubgraphSchema = Annotation.Root({
551
- ...MessagesAnnotation.spec,
552
- kind: Annotation<"weather" | "other">,
553
- });
554
-
555
- export const subgraph = new StateGraph(SubgraphSchema)
556
- .addNode("child", () => {
557
- return { messages: [new HumanMessage("Hello from child")] };
558
- })
559
- .addEdge("__start__", "child")
560
- `,
561
- ],
562
- ],
563
- },
564
- "graph",
565
- );
566
-
567
- expect(Object.keys(schemas)).toEqual(
568
- expect.arrayContaining(["graph", "graph|child"]),
569
- );
570
-
571
- expect(schemas["graph|child"].input).toMatchObject({
572
- type: "object",
573
- properties: {
574
- kind: {
575
- type: "string",
576
- enum: expect.arrayContaining(["weather", "other"]),
577
- },
578
- messages: {
579
- type: "array",
580
- items: { $ref: "#/definitions/BaseMessage" },
581
- },
582
- },
583
- definitions: {
584
- BaseMessage: {
585
- oneOf: expect.arrayContaining([
586
- { $ref: "#/definitions/BaseMessageChunk" },
587
- ]),
588
- },
589
- },
590
- $schema: "http://json-schema.org/draft-07/schema#",
591
- });
592
-
593
- expect(schemas["graph|child"].output).toMatchObject({
594
- type: "object",
595
- properties: {
596
- kind: {
597
- type: "string",
598
- enum: expect.arrayContaining(["weather", "other"]),
599
- },
600
- messages: {
601
- type: "array",
602
- items: { $ref: "#/definitions/BaseMessage" },
603
- },
604
- },
605
- definitions: {
606
- BaseMessage: {
607
- oneOf: expect.arrayContaining([
608
- { $ref: "#/definitions/BaseMessageChunk" },
609
- ]),
610
- },
611
- },
612
- $schema: "http://json-schema.org/draft-07/schema#",
613
- });
614
-
615
- expect(schemas["graph|child"].state).toMatchObject({
616
- type: "object",
617
- properties: {
618
- kind: {
619
- type: "string",
620
- enum: expect.arrayContaining(["weather", "other"]),
621
- },
622
- messages: {
623
- type: "array",
624
- items: { $ref: "#/definitions/BaseMessage" },
625
- },
626
- },
627
- definitions: {
628
- BaseMessage: {
629
- oneOf: expect.arrayContaining([
630
- { $ref: "#/definitions/BaseMessageChunk" },
631
- ]),
632
- },
633
- },
634
- $schema: "http://json-schema.org/draft-07/schema#",
635
- });
636
-
637
- expect(schemas["graph|child"].config).toMatchObject({
638
- type: "object",
639
- $schema: "http://json-schema.org/draft-07/schema#",
640
- });
641
- },
642
- );
643
-
644
- test.concurrent("indirect", { timeout: 10_000 }, () => {
645
- const schemas = SubgraphExtractor.extractSchemas(
646
- {
647
- contents: dedent`
648
- import { HumanMessage } from "@langchain/core/messages";
649
- import {
650
- Annotation,
651
- MessagesAnnotation,
652
- StateGraph,
653
- } from "@langchain/langgraph";
654
-
655
- const ParentSchema = MessagesAnnotation;
656
-
657
- const SubgraphSchema = Annotation.Root({
658
- ...MessagesAnnotation.spec,
659
- kind: Annotation<"weather" | "other">,
660
- });
661
-
662
- const subgraph = new StateGraph(SubgraphSchema)
663
- .addNode("child", () => {
664
- return { messages: [new HumanMessage("Hello from child")] };
665
- })
666
- .addEdge("__start__", "child")
667
- .compile();
668
-
669
- const parent = new StateGraph(ParentSchema)
670
- .addNode("parent", () => {
671
- return { messages: [new HumanMessage("Hello from child")] };
672
- })
673
- .addNode("child", subgraph)
674
- .addEdge("__start__", "parent")
675
- .addEdge("parent", "child")
676
- .addEdge("child", "__end__");
677
-
678
- const indirect1 = parent
679
- const indirect2 = (() => indirect1)()
680
- export const graph = parent.compile()
681
- `,
682
- },
683
- "graph",
684
- );
685
- expect(schemas["graph|child"].input).toMatchObject({
686
- type: "object",
687
- properties: {
688
- kind: {
689
- type: "string",
690
- enum: expect.arrayContaining(["weather", "other"]),
691
- },
692
- messages: {
693
- type: "array",
694
- items: { $ref: "#/definitions/BaseMessage" },
695
- },
696
- },
697
- definitions: {
698
- BaseMessage: {
699
- oneOf: expect.arrayContaining([
700
- { $ref: "#/definitions/BaseMessageChunk" },
701
- ]),
702
- },
703
- },
704
- $schema: "http://json-schema.org/draft-07/schema#",
705
- });
706
-
707
- expect(schemas["graph|child"].output).toMatchObject({
708
- type: "object",
709
- properties: {
710
- kind: {
711
- type: "string",
712
- enum: expect.arrayContaining(["weather", "other"]),
713
- },
714
- messages: {
715
- type: "array",
716
- items: { $ref: "#/definitions/BaseMessage" },
717
- },
718
- },
719
- definitions: {
720
- BaseMessage: {
721
- oneOf: expect.arrayContaining([
722
- { $ref: "#/definitions/BaseMessageChunk" },
723
- ]),
724
- },
725
- },
726
- $schema: "http://json-schema.org/draft-07/schema#",
727
- });
728
-
729
- expect(schemas["graph|child"].state).toMatchObject({
730
- type: "object",
731
- properties: {
732
- kind: {
733
- type: "string",
734
- enum: expect.arrayContaining(["weather", "other"]),
735
- },
736
- messages: {
737
- type: "array",
738
- items: { $ref: "#/definitions/BaseMessage" },
739
- },
740
- },
741
- definitions: {
742
- BaseMessage: {
743
- oneOf: expect.arrayContaining([
744
- { $ref: "#/definitions/BaseMessageChunk" },
745
- ]),
746
- },
747
- },
748
- $schema: "http://json-schema.org/draft-07/schema#",
749
- });
750
-
751
- expect(schemas["graph|child"].config).toMatchObject({
752
- type: "object",
753
- $schema: "http://json-schema.org/draft-07/schema#",
754
- });
755
- });
756
- });
757
-
758
- test.skipIf(isParserSkipped).concurrent("weather", { timeout: 20_000 }, () => {
759
- const schemas = SubgraphExtractor.extractSchemas(
760
- {
761
- contents: dedent`
762
- import { Annotation, StateGraph, END, START } from "@langchain/langgraph";
763
- import { MessagesAnnotation } from "@langchain/langgraph";
764
- import { AIMessage } from "@langchain/core/messages";
765
-
766
- const state = MessagesAnnotation;
767
-
768
- const weatherState = Annotation.Root({
769
- ...state.spec,
770
- city: Annotation<string>,
771
- });
772
-
773
- const routerState = Annotation.Root({
774
- ...state.spec,
775
- route: Annotation<"weather" | "other">,
776
- });
777
-
778
- const weather = new StateGraph(weatherState)
779
- .addNode("model_node", (state) => {
780
- const llm = new AIMessage({
781
- content: "",
782
- tool_calls: [
783
- {
784
- id: "tool_call123",
785
- name: "get_weather",
786
- args: { city: "San Francisco" },
787
- },
788
- ],
789
- });
790
-
791
- return { city: llm.tool_calls![0].args.city };
792
- })
793
- .addNode("weather_node", async (state) => {
794
- const result = \`It's sunny in $\{state.city}!\`;
795
- return { messages: [new AIMessage({ content: result })] };
796
- })
797
- .addEdge(START, "model_node")
798
- .addEdge("model_node", "weather_node")
799
- .addEdge("weather_node", END)
800
- .compile({ interruptBefore: ["weather_node"] });
801
-
802
- const router = new StateGraph(routerState)
803
- .addNode("router_node", async () => ({ route: "weather" }))
804
- .addNode("normal_llm_node", () => ({ messages: [new AIMessage("Hello")] }))
805
- .addNode("weather_graph", weather)
806
- .addEdge(START, "router_node")
807
- .addConditionalEdges(
808
- "router_node",
809
- ({ route }) => {
810
- if (route === "weather") return "weather_graph";
811
- return "normal_llm_node";
812
- },
813
- ["weather_graph", "normal_llm_node"]
814
- )
815
- .addEdge("weather_graph", END)
816
- .addEdge("normal_llm_node", END);
817
-
818
- export const graph = router.compile();
819
- `,
820
- },
821
- "graph",
822
- );
823
-
824
- expect(Object.keys(schemas)).toEqual(
825
- expect.arrayContaining(["graph", "graph|weather_graph"]),
826
- );
827
- });
828
-
829
- test.skipIf(isParserSkipped).concurrent("nested", { timeout: 10_000 }, () => {
830
- const schemas = SubgraphExtractor.extractSchemas(
831
- {
832
- contents: dedent`
833
- import { Annotation, StateGraph, END, START } from "@langchain/langgraph";
834
-
835
- const child = new StateGraph(
836
- Annotation.Root({
837
- messages: Annotation<string[]>({
838
- reducer: (a, b) => a.concat(b),
839
- }),
840
- child: Annotation<"child_one" | "child_two">,
841
- })
842
- )
843
- .addNode("c_one", () => ({ messages: ["Entered c_one node"] }))
844
- .addNode("c_two", () => ({ messages: ["Entered c_two node"] }))
845
- .addEdge(START, "c_one")
846
- .addEdge("c_one", "c_two")
847
- .addEdge("c_two", END);
848
-
849
- const parent = new StateGraph(
850
- Annotation.Root({
851
- messages: Annotation<string[]>({
852
- reducer: (a, b) => a.concat(b),
853
- }),
854
- parent: Annotation<"parent_one" | "parent_two">,
855
- })
856
- )
857
- .addNode("p_one", () => ({ messages: ["Entered p_one node"] }))
858
- .addNode("p_two", child.compile())
859
- .addEdge(START, "p_one")
860
- .addEdge("p_one", "p_two")
861
- .addEdge("p_two", END);
862
-
863
- const grandParent = new StateGraph(
864
- Annotation.Root({
865
- messages: Annotation<string[]>({
866
- reducer: (a, b) => a.concat(b),
867
- }),
868
- })
869
- )
870
- .addNode("gp_one", () => ({ messages: ["Entered gp_one node"] }))
871
- .addNode("gp_two", parent.compile())
872
- .addEdge(START, "gp_one")
873
- .addEdge("gp_one", "gp_two")
874
- .addEdge("gp_two", END);
875
-
876
- export const graph = grandParent.compile();
877
- `,
878
- },
879
- "graph",
880
- );
881
-
882
- expect(Object.keys(schemas)).toEqual(
883
- expect.arrayContaining(["graph", "graph|gp_two", "graph|gp_two|p_two"]),
884
- );
885
- });