@langchain/langgraph 0.2.27 → 0.2.28

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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._isCommand = exports.Command = exports._isSend = exports.Send = exports._isSendInterface = exports.CHECKPOINT_NAMESPACE_END = exports.CHECKPOINT_NAMESPACE_SEPARATOR = exports.RESERVED = exports.NULL_TASK_ID = exports.TASK_NAMESPACE = exports.PULL = exports.PUSH = exports.TASKS = exports.TAG_NOSTREAM = exports.TAG_HIDDEN = exports.RECURSION_LIMIT_DEFAULT = exports.RUNTIME_PLACEHOLDER = exports.RESUME = exports.INTERRUPT = exports.CONFIG_KEY_CHECKPOINT_MAP = exports.CONFIG_KEY_RESUME_VALUE = exports.CONFIG_KEY_STREAM = exports.CONFIG_KEY_TASK_ID = exports.CONFIG_KEY_RESUMING = exports.CONFIG_KEY_CHECKPOINTER = exports.CONFIG_KEY_READ = exports.CONFIG_KEY_SEND = exports.ERROR = exports.INPUT = exports.MISSING = void 0;
3
+ exports._isCommand = exports.Command = exports._isSend = exports.Send = exports._isSendInterface = exports.CHECKPOINT_NAMESPACE_END = exports.CHECKPOINT_NAMESPACE_SEPARATOR = exports.RESERVED = exports.NULL_TASK_ID = exports.TASK_NAMESPACE = exports.PULL = exports.PUSH = exports.TASKS = exports.SELF = exports.TAG_NOSTREAM = exports.TAG_HIDDEN = exports.RECURSION_LIMIT_DEFAULT = exports.RUNTIME_PLACEHOLDER = exports.RESUME = exports.INTERRUPT = exports.CONFIG_KEY_CHECKPOINT_MAP = exports.CONFIG_KEY_RESUME_VALUE = exports.CONFIG_KEY_STREAM = exports.CONFIG_KEY_TASK_ID = exports.CONFIG_KEY_RESUMING = exports.CONFIG_KEY_CHECKPOINTER = exports.CONFIG_KEY_READ = exports.CONFIG_KEY_SEND = exports.ERROR = exports.INPUT = exports.MISSING = void 0;
4
4
  exports.MISSING = Symbol.for("__missing__");
5
5
  exports.INPUT = "__input__";
6
6
  exports.ERROR = "__error__";
@@ -19,6 +19,7 @@ exports.RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
19
19
  exports.RECURSION_LIMIT_DEFAULT = 25;
20
20
  exports.TAG_HIDDEN = "langsmith:hidden";
21
21
  exports.TAG_NOSTREAM = "langsmith:nostream";
22
+ exports.SELF = "__self__";
22
23
  exports.TASKS = "__pregel_tasks";
23
24
  exports.PUSH = "__pregel_push";
24
25
  exports.PULL = "__pregel_pull";
@@ -117,7 +118,7 @@ class Send {
117
118
  exports.Send = Send;
118
119
  function _isSend(x) {
119
120
  const operation = x;
120
- return operation.lg_name === "Send";
121
+ return operation !== undefined && operation.lg_name === "Send";
121
122
  }
122
123
  exports._isSend = _isSend;
123
124
  class Command {
@@ -134,10 +135,40 @@ class Command {
134
135
  writable: true,
135
136
  value: void 0
136
137
  });
138
+ Object.defineProperty(this, "graph", {
139
+ enumerable: true,
140
+ configurable: true,
141
+ writable: true,
142
+ value: void 0
143
+ });
144
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
+ Object.defineProperty(this, "update", {
146
+ enumerable: true,
147
+ configurable: true,
148
+ writable: true,
149
+ value: void 0
150
+ });
151
+ Object.defineProperty(this, "goto", {
152
+ enumerable: true,
153
+ configurable: true,
154
+ writable: true,
155
+ value: []
156
+ });
137
157
  this.resume = args.resume;
158
+ this.graph = args.graph;
159
+ this.update = args.update;
160
+ if (args.goto) {
161
+ this.goto = Array.isArray(args.goto) ? args.goto : [args.goto];
162
+ }
138
163
  }
139
164
  }
140
165
  exports.Command = Command;
166
+ Object.defineProperty(Command, "PARENT", {
167
+ enumerable: true,
168
+ configurable: true,
169
+ writable: true,
170
+ value: "__parent__"
171
+ });
141
172
  function _isCommand(x) {
142
173
  return typeof x === "object" && !!x && x.lg_name === "Command";
143
174
  }
@@ -15,6 +15,7 @@ export declare const RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
15
15
  export declare const RECURSION_LIMIT_DEFAULT = 25;
16
16
  export declare const TAG_HIDDEN = "langsmith:hidden";
17
17
  export declare const TAG_NOSTREAM = "langsmith:nostream";
18
+ export declare const SELF = "__self__";
18
19
  export declare const TASKS = "__pregel_tasks";
19
20
  export declare const PUSH = "__pregel_push";
20
21
  export declare const PULL = "__pregel_pull";
@@ -87,11 +88,19 @@ export type Interrupt = {
87
88
  resumable?: boolean;
88
89
  ns?: string[];
89
90
  };
91
+ export type CommandParams<R> = {
92
+ resume?: R;
93
+ graph?: string;
94
+ update?: Record<string, any>;
95
+ goto?: string | Send | (string | Send)[];
96
+ };
90
97
  export declare class Command<R = unknown> {
91
98
  lg_name: string;
92
- resume: R;
93
- constructor(args: {
94
- resume: R;
95
- });
99
+ resume?: R;
100
+ graph?: string;
101
+ update?: Record<string, any>;
102
+ goto: string | Send | (string | Send)[];
103
+ static PARENT: string;
104
+ constructor(args: CommandParams<R>);
96
105
  }
97
106
  export declare function _isCommand(x: unknown): x is Command;
package/dist/constants.js CHANGED
@@ -16,6 +16,7 @@ export const RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__";
16
16
  export const RECURSION_LIMIT_DEFAULT = 25;
17
17
  export const TAG_HIDDEN = "langsmith:hidden";
18
18
  export const TAG_NOSTREAM = "langsmith:nostream";
19
+ export const SELF = "__self__";
19
20
  export const TASKS = "__pregel_tasks";
20
21
  export const PUSH = "__pregel_push";
21
22
  export const PULL = "__pregel_pull";
@@ -112,7 +113,7 @@ export class Send {
112
113
  }
113
114
  export function _isSend(x) {
114
115
  const operation = x;
115
- return operation.lg_name === "Send";
116
+ return operation !== undefined && operation.lg_name === "Send";
116
117
  }
117
118
  export class Command {
118
119
  constructor(args) {
@@ -128,9 +129,39 @@ export class Command {
128
129
  writable: true,
129
130
  value: void 0
130
131
  });
132
+ Object.defineProperty(this, "graph", {
133
+ enumerable: true,
134
+ configurable: true,
135
+ writable: true,
136
+ value: void 0
137
+ });
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ Object.defineProperty(this, "update", {
140
+ enumerable: true,
141
+ configurable: true,
142
+ writable: true,
143
+ value: void 0
144
+ });
145
+ Object.defineProperty(this, "goto", {
146
+ enumerable: true,
147
+ configurable: true,
148
+ writable: true,
149
+ value: []
150
+ });
131
151
  this.resume = args.resume;
152
+ this.graph = args.graph;
153
+ this.update = args.update;
154
+ if (args.goto) {
155
+ this.goto = Array.isArray(args.goto) ? args.goto : [args.goto];
156
+ }
132
157
  }
133
158
  }
159
+ Object.defineProperty(Command, "PARENT", {
160
+ enumerable: true,
161
+ configurable: true,
162
+ writable: true,
163
+ value: "__parent__"
164
+ });
134
165
  export function _isCommand(x) {
135
166
  return typeof x === "object" && !!x && x.lg_name === "Command";
136
167
  }
package/dist/errors.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSubgraphsSeenSet = exports.RemoteException = exports.MultipleSubgraphsError = exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.isGraphInterrupt = exports.isGraphBubbleUp = exports.NodeInterrupt = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = exports.GraphBubbleUp = exports.BaseLangGraphError = void 0;
3
+ exports.getSubgraphsSeenSet = exports.RemoteException = exports.MultipleSubgraphsError = exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.isGraphInterrupt = exports.isGraphBubbleUp = exports.isParentCommand = exports.ParentCommand = exports.NodeInterrupt = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = exports.GraphBubbleUp = exports.BaseLangGraphError = void 0;
4
4
  // TODO: Merge with base LangChain error class when we drop support for core@0.2.0
5
5
  class BaseLangGraphError extends Error {
6
6
  constructor(message, fields) {
@@ -79,6 +79,28 @@ class NodeInterrupt extends GraphInterrupt {
79
79
  }
80
80
  }
81
81
  exports.NodeInterrupt = NodeInterrupt;
82
+ class ParentCommand extends GraphBubbleUp {
83
+ constructor(command) {
84
+ super();
85
+ Object.defineProperty(this, "command", {
86
+ enumerable: true,
87
+ configurable: true,
88
+ writable: true,
89
+ value: void 0
90
+ });
91
+ this.name = "ParentCommand";
92
+ this.command = command;
93
+ }
94
+ static get unminifiable_name() {
95
+ return "ParentCommand";
96
+ }
97
+ }
98
+ exports.ParentCommand = ParentCommand;
99
+ function isParentCommand(e) {
100
+ return (e !== undefined &&
101
+ e.name === ParentCommand.unminifiable_name);
102
+ }
103
+ exports.isParentCommand = isParentCommand;
82
104
  function isGraphBubbleUp(e) {
83
105
  return e !== undefined && e.is_bubble_up === true;
84
106
  }
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Interrupt } from "./constants.js";
1
+ import { Command, Interrupt } from "./constants.js";
2
2
  export type BaseLangGraphErrorFields = {
3
3
  lc_error_code?: string;
4
4
  };
@@ -27,6 +27,12 @@ export declare class NodeInterrupt extends GraphInterrupt {
27
27
  constructor(message: any, fields?: BaseLangGraphErrorFields);
28
28
  static get unminifiable_name(): string;
29
29
  }
30
+ export declare class ParentCommand extends GraphBubbleUp {
31
+ command: Command;
32
+ constructor(command: Command);
33
+ static get unminifiable_name(): string;
34
+ }
35
+ export declare function isParentCommand(e?: Error): e is ParentCommand;
30
36
  export declare function isGraphBubbleUp(e?: Error): e is GraphBubbleUp;
31
37
  export declare function isGraphInterrupt(e?: GraphInterrupt | Error): e is GraphInterrupt;
32
38
  export declare class EmptyInputError extends BaseLangGraphError {
package/dist/errors.js CHANGED
@@ -70,6 +70,26 @@ export class NodeInterrupt extends GraphInterrupt {
70
70
  return "NodeInterrupt";
71
71
  }
72
72
  }
73
+ export class ParentCommand extends GraphBubbleUp {
74
+ constructor(command) {
75
+ super();
76
+ Object.defineProperty(this, "command", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: void 0
81
+ });
82
+ this.name = "ParentCommand";
83
+ this.command = command;
84
+ }
85
+ static get unminifiable_name() {
86
+ return "ParentCommand";
87
+ }
88
+ }
89
+ export function isParentCommand(e) {
90
+ return (e !== undefined &&
91
+ e.name === ParentCommand.unminifiable_name);
92
+ }
73
93
  export function isGraphBubbleUp(e) {
74
94
  return e !== undefined && e.is_bubble_up === true;
75
95
  }
@@ -32,7 +32,14 @@ class Branch {
32
32
  writable: true,
33
33
  value: void 0
34
34
  });
35
- this.condition = options.path;
35
+ if (runnables_1.Runnable.isRunnable(options.path)) {
36
+ this.condition = options.path;
37
+ }
38
+ else {
39
+ this.condition = (0, runnables_1._coerceToRunnable)(options.path).withConfig({
40
+ runName: `Branch`,
41
+ });
42
+ }
36
43
  this.ends = Array.isArray(options.pathMap)
37
44
  ? options.pathMap.reduce((acc, n) => {
38
45
  acc[n] = n;
@@ -40,7 +47,7 @@ class Branch {
40
47
  }, {})
41
48
  : options.pathMap;
42
49
  }
43
- compile(writer, reader) {
50
+ run(writer, reader) {
44
51
  return write_js_1.ChannelWrite.registerWriter(new utils_js_1.RunnableCallable({
45
52
  trace: false,
46
53
  func: async (input, config) => {
@@ -59,8 +66,10 @@ class Branch {
59
66
  },
60
67
  }));
61
68
  }
62
- async _route(input, config, writer, reader) {
63
- let result = await this.condition(reader ? reader(config) : input, config);
69
+ async _route(input, config, writer, reader
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ ) {
72
+ let result = await this.condition.invoke(reader ? reader(config) : input, config);
64
73
  if (!Array.isArray(result)) {
65
74
  result = [result];
66
75
  }
@@ -77,7 +86,8 @@ class Branch {
77
86
  if (destinations.filter(constants_js_1._isSend).some((packet) => packet.node === exports.END)) {
78
87
  throw new errors_js_1.InvalidUpdateError("Cannot send a packet to the END node");
79
88
  }
80
- return writer(destinations);
89
+ const writeResult = await writer(destinations, config);
90
+ return writeResult ?? input;
81
91
  }
82
92
  }
83
93
  exports.Branch = Branch;
@@ -168,10 +178,26 @@ class Graph {
168
178
  return this;
169
179
  }
170
180
  addConditionalEdges(source, path, pathMap) {
171
- const options = typeof source === "object" ? source : { source, path: path, pathMap };
181
+ const options = typeof source === "object"
182
+ ? source
183
+ : {
184
+ source,
185
+ path: path,
186
+ pathMap,
187
+ };
172
188
  this.warnIfCompiled("Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.");
189
+ if (!runnables_1.Runnable.isRunnable(options.path)) {
190
+ const pathDisplayValues = Array.isArray(options.pathMap)
191
+ ? options.pathMap.join(",")
192
+ : Object.keys(options.pathMap ?? {}).join(",");
193
+ options.path = (0, runnables_1._coerceToRunnable)(options.path).withConfig({
194
+ runName: `Branch<${options.source}${pathDisplayValues !== "" ? `,${pathDisplayValues}` : ""}>`.slice(0, 63),
195
+ });
196
+ }
173
197
  // find a name for condition
174
- const name = options.path.name || "condition";
198
+ const name = options.path.getName() === "RunnableLambda"
199
+ ? "condition"
200
+ : options.path.getName();
175
201
  // validate condition
176
202
  if (this.branches[options.source] && this.branches[options.source][name]) {
177
203
  throw new Error(`Condition \`${name}\` already present for node \`${source}\``);
@@ -328,7 +354,7 @@ class CompiledGraph extends index_js_1.Pregel {
328
354
  this.nodes[exports.START] = index_js_1.Channel.subscribeTo(exports.START, { tags: [constants_js_1.TAG_HIDDEN] });
329
355
  }
330
356
  // attach branch writer
331
- this.nodes[start].pipe(branch.compile((dests) => {
357
+ this.nodes[start].pipe(branch.run((dests) => {
332
358
  const writes = dests.map((dest) => {
333
359
  if ((0, constants_js_1._isSend)(dest)) {
334
360
  return dest;
@@ -15,15 +15,16 @@ export declare const START = "__start__";
15
15
  export declare const END = "__end__";
16
16
  export interface BranchOptions<IO, N extends string, CallOptions extends LangGraphRunnableConfig = LangGraphRunnableConfig> {
17
17
  source: N;
18
- path: Branch<IO, N, CallOptions>["condition"];
18
+ path: RunnableLike<IO, BranchPathReturnValue, CallOptions>;
19
19
  pathMap?: Record<string, N | typeof END> | (N | typeof END)[];
20
20
  }
21
+ export type BranchPathReturnValue = string | Send | (string | Send)[] | Promise<string | Send | (string | Send)[]>;
21
22
  export declare class Branch<IO, N extends string, CallOptions extends LangGraphRunnableConfig = LangGraphRunnableConfig> {
22
- condition: (input: IO, config: CallOptions) => string | Send | (string | Send)[] | Promise<string | Send | (string | Send)[]>;
23
+ condition: Runnable<IO, BranchPathReturnValue, CallOptions>;
23
24
  ends?: Record<string, N | typeof END>;
24
25
  constructor(options: Omit<BranchOptions<IO, N, CallOptions>, "source">);
25
- compile(writer: (dests: (string | Send)[]) => Runnable | undefined, reader?: (config: CallOptions) => IO): RunnableCallable<unknown, unknown>;
26
- _route(input: IO, config: CallOptions, writer: (dests: (string | Send)[]) => Runnable | undefined, reader?: (config: CallOptions) => IO): Promise<Runnable | undefined>;
26
+ run(writer: (dests: (string | Send)[], config: LangGraphRunnableConfig) => Runnable | void | Promise<void>, reader?: (config: CallOptions) => IO): RunnableCallable<unknown, unknown>;
27
+ _route(input: IO, config: CallOptions, writer: (dests: (string | Send)[], config: LangGraphRunnableConfig) => Runnable | void | Promise<void>, reader?: (config: CallOptions) => IO): Promise<Runnable | any>;
27
28
  }
28
29
  export type NodeSpec<RunInput, RunOutput> = {
29
30
  runnable: Runnable<RunInput, RunOutput>;
@@ -46,7 +47,7 @@ export declare class Graph<N extends string = typeof END, RunInput = any, RunOut
46
47
  addNode<K extends string, NodeInput = RunInput>(key: K, action: RunnableLike<NodeInput, RunOutput extends object ? RunOutput & Record<string, any> : RunOutput, LangGraphRunnableConfig<StateType<C>>>, options?: AddNodeOptions): Graph<N | K, RunInput, RunOutput>;
47
48
  addEdge(startKey: N | typeof START, endKey: N | typeof END): this;
48
49
  addConditionalEdges(source: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>): this;
49
- addConditionalEdges(source: N, path: Branch<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["condition"], pathMap?: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["pathMap"]): this;
50
+ addConditionalEdges(source: N, path: RunnableLike<RunInput, BranchPathReturnValue, LangGraphRunnableConfig<StateType<C>>>, pathMap?: BranchOptions<RunInput, N, LangGraphRunnableConfig<StateType<C>>>["pathMap"]): this;
50
51
  /**
51
52
  * @deprecated use `addEdge(START, key)` instead
52
53
  */
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
- import { _coerceToRunnable, } from "@langchain/core/runnables";
2
+ import { _coerceToRunnable, Runnable, } from "@langchain/core/runnables";
3
3
  import { Graph as DrawableGraph, } from "@langchain/core/runnables/graph";
4
4
  import { z } from "zod";
5
5
  import { validate as isUuid } from "uuid";
@@ -29,7 +29,14 @@ export class Branch {
29
29
  writable: true,
30
30
  value: void 0
31
31
  });
32
- this.condition = options.path;
32
+ if (Runnable.isRunnable(options.path)) {
33
+ this.condition = options.path;
34
+ }
35
+ else {
36
+ this.condition = _coerceToRunnable(options.path).withConfig({
37
+ runName: `Branch`,
38
+ });
39
+ }
33
40
  this.ends = Array.isArray(options.pathMap)
34
41
  ? options.pathMap.reduce((acc, n) => {
35
42
  acc[n] = n;
@@ -37,7 +44,7 @@ export class Branch {
37
44
  }, {})
38
45
  : options.pathMap;
39
46
  }
40
- compile(writer, reader) {
47
+ run(writer, reader) {
41
48
  return ChannelWrite.registerWriter(new RunnableCallable({
42
49
  trace: false,
43
50
  func: async (input, config) => {
@@ -56,8 +63,10 @@ export class Branch {
56
63
  },
57
64
  }));
58
65
  }
59
- async _route(input, config, writer, reader) {
60
- let result = await this.condition(reader ? reader(config) : input, config);
66
+ async _route(input, config, writer, reader
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ ) {
69
+ let result = await this.condition.invoke(reader ? reader(config) : input, config);
61
70
  if (!Array.isArray(result)) {
62
71
  result = [result];
63
72
  }
@@ -74,7 +83,8 @@ export class Branch {
74
83
  if (destinations.filter(_isSend).some((packet) => packet.node === END)) {
75
84
  throw new InvalidUpdateError("Cannot send a packet to the END node");
76
85
  }
77
- return writer(destinations);
86
+ const writeResult = await writer(destinations, config);
87
+ return writeResult ?? input;
78
88
  }
79
89
  }
80
90
  export class Graph {
@@ -164,10 +174,26 @@ export class Graph {
164
174
  return this;
165
175
  }
166
176
  addConditionalEdges(source, path, pathMap) {
167
- const options = typeof source === "object" ? source : { source, path: path, pathMap };
177
+ const options = typeof source === "object"
178
+ ? source
179
+ : {
180
+ source,
181
+ path: path,
182
+ pathMap,
183
+ };
168
184
  this.warnIfCompiled("Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.");
185
+ if (!Runnable.isRunnable(options.path)) {
186
+ const pathDisplayValues = Array.isArray(options.pathMap)
187
+ ? options.pathMap.join(",")
188
+ : Object.keys(options.pathMap ?? {}).join(",");
189
+ options.path = _coerceToRunnable(options.path).withConfig({
190
+ runName: `Branch<${options.source}${pathDisplayValues !== "" ? `,${pathDisplayValues}` : ""}>`.slice(0, 63),
191
+ });
192
+ }
169
193
  // find a name for condition
170
- const name = options.path.name || "condition";
194
+ const name = options.path.getName() === "RunnableLambda"
195
+ ? "condition"
196
+ : options.path.getName();
171
197
  // validate condition
172
198
  if (this.branches[options.source] && this.branches[options.source][name]) {
173
199
  throw new Error(`Condition \`${name}\` already present for node \`${source}\``);
@@ -323,7 +349,7 @@ export class CompiledGraph extends Pregel {
323
349
  this.nodes[START] = Channel.subscribeTo(START, { tags: [TAG_HIDDEN] });
324
350
  }
325
351
  // attach branch writer
326
- this.nodes[start].pipe(branch.compile((dests) => {
352
+ this.nodes[start].pipe(branch.run((dests) => {
327
353
  const writes = dests.map((dest) => {
328
354
  if (_isSend(dest)) {
329
355
  return dest;
@@ -303,6 +303,14 @@ class StateGraph extends graph_js_1.Graph {
303
303
  for (const [key, node] of Object.entries(this.nodes)) {
304
304
  compiled.attachNode(key, node);
305
305
  }
306
+ compiled.attachBranch(graph_js_1.START, constants_js_1.SELF, _getControlBranch(), {
307
+ withReader: false,
308
+ });
309
+ for (const [key] of Object.entries(this.nodes)) {
310
+ compiled.attachBranch(key, constants_js_1.SELF, _getControlBranch(), {
311
+ withReader: false,
312
+ });
313
+ }
306
314
  for (const [start, end] of this.edges) {
307
315
  compiled.attachEdge(start, end);
308
316
  }
@@ -339,13 +347,30 @@ function _getChannels(schema) {
339
347
  class CompiledStateGraph extends graph_js_1.CompiledGraph {
340
348
  attachNode(key, node) {
341
349
  const stateKeys = Object.keys(this.builder.channels);
350
+ function _getRoot(input) {
351
+ if ((0, constants_js_1._isCommand)(input)) {
352
+ if (input.graph === constants_js_1.Command.PARENT) {
353
+ return write_js_1.SKIP_WRITE;
354
+ }
355
+ return input.update;
356
+ }
357
+ return input;
358
+ }
359
+ // to avoid name collision below
360
+ const nodeKey = key;
342
361
  function getStateKey(key, input) {
343
362
  if (!input) {
344
363
  return write_js_1.SKIP_WRITE;
345
364
  }
365
+ else if ((0, constants_js_1._isCommand)(input)) {
366
+ if (input.graph === constants_js_1.Command.PARENT) {
367
+ return write_js_1.SKIP_WRITE;
368
+ }
369
+ return getStateKey(key, input.update);
370
+ }
346
371
  else if (typeof input !== "object" || Array.isArray(input)) {
347
372
  const typeofInput = Array.isArray(input) ? "array" : typeof input;
348
- throw new errors_js_1.InvalidUpdateError(`Expected node "${key.toString()}" to return an object, received ${typeofInput}`, {
373
+ throw new errors_js_1.InvalidUpdateError(`Expected node "${nodeKey.toString()}" to return an object, received ${typeofInput}`, {
349
374
  lc_error_code: "INVALID_GRAPH_NODE_RETURN_VALUE",
350
375
  });
351
376
  }
@@ -355,7 +380,16 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
355
380
  }
356
381
  // state updaters
357
382
  const stateWriteEntries = stateKeys.map((key) => key === ROOT
358
- ? { channel: key, value: write_js_1.PASSTHROUGH, skipNone: true }
383
+ ? {
384
+ channel: key,
385
+ value: write_js_1.PASSTHROUGH,
386
+ skipNone: true,
387
+ mapper: new utils_js_1.RunnableCallable({
388
+ func: _getRoot,
389
+ trace: false,
390
+ recurse: false,
391
+ }),
392
+ }
359
393
  : {
360
394
  channel: key,
361
395
  value: write_js_1.PASSTHROUGH,
@@ -430,28 +464,29 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
430
464
  this.nodes[end].triggers.push(start);
431
465
  }
432
466
  }
433
- attachBranch(start, name, branch) {
434
- // attach branch publisher
435
- this.nodes[start].writers.push(branch.compile(
436
- // writer
437
- (dests) => {
438
- const filteredDests = dests.filter((dest) => dest !== graph_js_1.END);
439
- if (!filteredDests.length) {
467
+ attachBranch(start, name, branch, options = { withReader: true }) {
468
+ const branchWriter = async (packets, config) => {
469
+ const filteredPackets = packets.filter((p) => p !== graph_js_1.END);
470
+ if (!filteredPackets.length) {
440
471
  return;
441
472
  }
442
- const writes = filteredDests.map((dest) => {
443
- if ((0, constants_js_1._isSend)(dest)) {
444
- return dest;
473
+ const writes = filteredPackets.map((p) => {
474
+ if ((0, constants_js_1._isSend)(p)) {
475
+ return p;
445
476
  }
446
477
  return {
447
- channel: `branch:${start}:${name}:${dest}`,
478
+ channel: `branch:${start}:${name}:${p}`,
448
479
  value: start,
449
480
  };
450
481
  });
451
- return new write_js_1.ChannelWrite(writes, [constants_js_1.TAG_HIDDEN]);
452
- },
482
+ await write_js_1.ChannelWrite.doWrite({ ...config, tags: (config.tags ?? []).concat([constants_js_1.TAG_HIDDEN]) }, writes);
483
+ };
484
+ // attach branch publisher
485
+ this.nodes[start].writers.push(branch.run(branchWriter,
453
486
  // reader
454
- (config) => read_js_1.ChannelRead.doRead(config, this.streamChannels ?? this.outputChannels, true)));
487
+ options.withReader
488
+ ? (config) => read_js_1.ChannelRead.doRead(config, this.streamChannels ?? this.outputChannels, true)
489
+ : undefined));
455
490
  // attach branch subscribers
456
491
  const ends = branch.ends
457
492
  ? Object.values(branch.ends)
@@ -499,3 +534,28 @@ function isStateGraphArgsWithInputOutputSchemas(obj) {
499
534
  obj.input !== undefined &&
500
535
  obj.output !== undefined);
501
536
  }
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ function _controlBranch(value) {
539
+ if ((0, constants_js_1._isSend)(value)) {
540
+ return [value];
541
+ }
542
+ if (!(0, constants_js_1._isCommand)(value)) {
543
+ return [];
544
+ }
545
+ if (value.graph === constants_js_1.Command.PARENT) {
546
+ throw new errors_js_1.ParentCommand(value);
547
+ }
548
+ return Array.isArray(value.goto) ? value.goto : [value.goto];
549
+ }
550
+ function _getControlBranch() {
551
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
552
+ const CONTROL_BRANCH_PATH = new utils_js_1.RunnableCallable({
553
+ func: _controlBranch,
554
+ tags: [constants_js_1.TAG_HIDDEN],
555
+ trace: false,
556
+ recurse: false,
557
+ });
558
+ return new graph_js_1.Branch({
559
+ path: CONTROL_BRANCH_PATH,
560
+ });
561
+ }
@@ -133,5 +133,7 @@ export declare class CompiledStateGraph<S, U, N extends string = typeof START, I
133
133
  attachNode(key: typeof START, node?: never): void;
134
134
  attachNode(key: N, node: StateGraphNodeSpec<S, U>): void;
135
135
  attachEdge(start: N | N[] | "__start__", end: N | "__end__"): void;
136
- attachBranch(start: N | typeof START, name: string, branch: Branch<S, N>): void;
136
+ attachBranch(start: N | typeof START, name: string, branch: Branch<S, N>, options?: {
137
+ withReader?: boolean;
138
+ }): void;
137
139
  }