@langchain/langgraph 0.0.31 → 0.0.33

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.
Files changed (42) hide show
  1. package/README.md +75 -28
  2. package/dist/channels/base.cjs +14 -0
  3. package/dist/channels/base.d.ts +2 -0
  4. package/dist/channels/base.js +14 -0
  5. package/dist/graph/message.d.ts +1 -1
  6. package/dist/graph/state.cjs +36 -2
  7. package/dist/graph/state.d.ts +23 -9
  8. package/dist/graph/state.js +34 -1
  9. package/dist/prebuilt/agent_executor.d.ts +1 -1
  10. package/dist/pregel/index.cjs +26 -21
  11. package/dist/pregel/index.js +26 -21
  12. package/package.json +9 -16
  13. package/dist/tests/channels.test.d.ts +0 -1
  14. package/dist/tests/channels.test.js +0 -151
  15. package/dist/tests/chatbot.int.test.d.ts +0 -1
  16. package/dist/tests/chatbot.int.test.js +0 -66
  17. package/dist/tests/checkpoints.test.d.ts +0 -1
  18. package/dist/tests/checkpoints.test.js +0 -178
  19. package/dist/tests/diagrams.test.d.ts +0 -1
  20. package/dist/tests/diagrams.test.js +0 -25
  21. package/dist/tests/graph.test.d.ts +0 -1
  22. package/dist/tests/graph.test.js +0 -33
  23. package/dist/tests/prebuilt.int.test.d.ts +0 -1
  24. package/dist/tests/prebuilt.int.test.js +0 -207
  25. package/dist/tests/prebuilt.test.d.ts +0 -1
  26. package/dist/tests/prebuilt.test.js +0 -427
  27. package/dist/tests/pregel.io.test.d.ts +0 -1
  28. package/dist/tests/pregel.io.test.js +0 -332
  29. package/dist/tests/pregel.read.test.d.ts +0 -1
  30. package/dist/tests/pregel.read.test.js +0 -109
  31. package/dist/tests/pregel.test.d.ts +0 -1
  32. package/dist/tests/pregel.test.js +0 -1882
  33. package/dist/tests/pregel.validate.test.d.ts +0 -1
  34. package/dist/tests/pregel.validate.test.js +0 -198
  35. package/dist/tests/pregel.write.test.d.ts +0 -1
  36. package/dist/tests/pregel.write.test.js +0 -44
  37. package/dist/tests/tracing.int.test.d.ts +0 -1
  38. package/dist/tests/tracing.int.test.js +0 -450
  39. package/dist/tests/tracing.test.d.ts +0 -1
  40. package/dist/tests/tracing.test.js +0 -332
  41. package/dist/tests/utils.d.ts +0 -53
  42. package/dist/tests/utils.js +0 -167
package/README.md CHANGED
@@ -4,7 +4,6 @@
4
4
  ![Version](https://img.shields.io/npm/v/@langchain/langgraph?logo=npm)
5
5
  [![Downloads](https://img.shields.io/npm/dm/@langchain/langgraph)](https://www.npmjs.com/package/@langchain/langgraph)
6
6
  [![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraphjs)](https://github.com/langchain-ai/langgraphjs/issues)
7
- [![](https://dcbadge.vercel.app/api/server/6adMQxSpJS?compact=true&style=flat)](https://discord.com/channels/1038097195422978059/1170024642245832774)
8
7
 
9
8
  ⚡ Building language agents as graphs ⚡
10
9
 
@@ -56,55 +55,52 @@ export LANGCHAIN_API_KEY=ls__...
56
55
  Now let's define our agent:
57
56
 
58
57
  ```typescript
59
- import { HumanMessage, AIMessage } from "@langchain/core/messages";
60
- import { DynamicStructuredTool } from "@langchain/core/tools";
58
+ import { AIMessage, BaseMessage, HumanMessage } from "@langchain/core/messages";
59
+ import { tool } from "@langchain/core/tools";
61
60
  import { z } from "zod";
62
61
  import { ChatAnthropic } from "@langchain/anthropic";
63
- import { END, START, StateGraph, StateGraphArgs } from "@langchain/langgraph";
62
+ import { StateGraph, StateGraphArgs } from "@langchain/langgraph";
64
63
  import { MemorySaver } from "@langchain/langgraph";
65
64
  import { ToolNode } from "@langchain/langgraph/prebuilt";
66
65
 
67
66
  // Define the state interface
68
67
  interface AgentState {
69
- messages: HumanMessage[];
68
+ messages: BaseMessage[];
70
69
  }
71
70
 
72
71
  // Define the graph state
73
72
  const graphState: StateGraphArgs<AgentState>["channels"] = {
74
73
  messages: {
75
- value: (x: HumanMessage[], y: HumanMessage[]) => x.concat(y),
76
- default: () => [],
74
+ reducer: (x: BaseMessage[], y: BaseMessage[]) => x.concat(y),
77
75
  },
78
76
  };
79
77
 
80
78
  // Define the tools for the agent to use
81
-
82
- const searchTool = new DynamicStructuredTool({
83
- name: "search",
79
+ const weatherTool = tool(async ({ query }) => {
80
+ // This is a placeholder for the actual implementation
81
+ if (query.toLowerCase().includes("sf") || query.toLowerCase().includes("san francisco")) {
82
+ return "It's 60 degrees and foggy."
83
+ }
84
+ return "It's 90 degrees and sunny."
85
+ }, {
86
+ name: "weather",
84
87
  description:
85
- "Call to surf the web.",
88
+ "Call to get the current weather for a location.",
86
89
  schema: z.object({
87
90
  query: z.string().describe("The query to use in your search."),
88
91
  }),
89
- func: async ({ query }: { query: string }) => {
90
- // This is a placeholder for the actual implementation
91
- if (query.toLowerCase().includes("sf") || query.toLowerCase().includes("san francisco")) {
92
- return "It's 60 degrees and foggy."
93
- }
94
- return "It's 90 degrees and sunny."
95
- },
96
92
  });
97
93
 
98
- const tools = [searchTool];
94
+ const tools = [weatherTool];
99
95
  const toolNode = new ToolNode<AgentState>(tools);
100
96
 
101
97
  const model = new ChatAnthropic({
102
- model: "claude-3-sonnet-20240229",
98
+ model: "claude-3-5-sonnet-20240620",
103
99
  temperature: 0,
104
100
  }).bindTools(tools);
105
101
 
106
102
  // Define the function that determines whether to continue or not
107
- function shouldContinue(state: AgentState): "tools" | typeof END {
103
+ function shouldContinue(state: AgentState) {
108
104
  const messages = state.messages;
109
105
  const lastMessage = messages[messages.length - 1] as AIMessage;
110
106
 
@@ -113,7 +109,7 @@ function shouldContinue(state: AgentState): "tools" | typeof END {
113
109
  return "tools";
114
110
  }
115
111
  // Otherwise, we stop (reply to the user)
116
- return END;
112
+ return "__end__";
117
113
  }
118
114
 
119
115
  // Define the function that calls the model
@@ -129,7 +125,7 @@ async function callModel(state: AgentState) {
129
125
  const workflow = new StateGraph<AgentState>({ channels: graphState })
130
126
  .addNode("agent", callModel)
131
127
  .addNode("tools", toolNode)
132
- .addEdge(START, "agent")
128
+ .addEdge("__start__", "agent")
133
129
  .addConditionalEdges("agent", shouldContinue)
134
130
  .addEdge("tools", "agent");
135
131
 
@@ -146,13 +142,21 @@ const finalState = await app.invoke(
146
142
  { messages: [new HumanMessage("what is the weather in sf")] },
147
143
  { configurable: { thread_id: "42" } }
148
144
  );
145
+
149
146
  console.log(finalState.messages[finalState.messages.length - 1].content);
150
147
  ```
151
148
 
152
149
  This will output:
153
150
 
154
151
  ```
155
- Based on the search results, I can tell you that the current weather in San Francisco is:\n\nTemperature: 60 degrees Fahrenheit\nConditions: Foggy\n\nSan Francisco is known for its microclimates and frequent fog, especially during the summer months. The temperature of 60°F (about 15.5°C) is quite typical for the city, which tends to have mild temperatures year-round. The fog, often referred to as "Karl the Fog" by locals, is a characteristic feature of San Francisco\'s weather, particularly in the mornings and evenings.\n\nIs there anything else you\'d like to know about the weather in San Francisco or any other location?
152
+ Based on the information I received, the current weather in San Francisco is:
153
+
154
+ Temperature: 60 degrees Fahrenheit
155
+ Conditions: Foggy
156
+
157
+ San Francisco is known for its foggy weather, especially during certain times of the year. The moderate temperature of 60°F (about 15.5°C) is quite typical for the city, which generally has mild weather year-round due to its coastal location.
158
+
159
+ Is there anything else you'd like to know about the weather in San Francisco or any other location?
156
160
  ```
157
161
 
158
162
  Now when we pass the same `"thread_id"`, the conversation context is retained via the saved state (i.e. stored list of messages):
@@ -166,7 +170,16 @@ console.log(nextState.messages[nextState.messages.length - 1].content);
166
170
  ```
167
171
 
168
172
  ```
169
- Based on the search results, I can tell you that the current weather in New York City is:\n\nTemperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)\nConditions: Sunny\n\nThis weather is quite different from what we just saw in San Francisco. New York is experiencing much warmer temperatures right now. Here are a few points to note:\n\n1. The temperature of 90°F is quite hot, typical of summer weather in New York City.\n2. The sunny conditions suggest clear skies, which is great for outdoor activities but also means it might feel even hotter due to direct sunlight.\n3. This kind of weather in New York often comes with high humidity, which can make it feel even warmer than the actual temperature suggests.\n\nIt's interesting to see the stark contrast between San Francisco's mild, foggy weather and New York's hot, sunny conditions. This difference illustrates how varied weather can be across different parts of the United States, even on the same day.\n\nIs there anything else you'd like to know about the weather in New York or any other location?
173
+ Based on the information I received, the current weather in New York is:
174
+
175
+ Temperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)
176
+ Conditions: Sunny
177
+
178
+ New York is experiencing quite warm weather today. A temperature of 90°F is considered hot for most people, and it's significantly warmer than the San Francisco weather we just checked. The sunny conditions suggest it's a clear day without cloud cover, which can make it feel even warmer.
179
+
180
+ On a day like this in New York, it would be advisable for people to stay hydrated, seek shade when possible, and use sun protection if spending time outdoors.
181
+
182
+ Is there anything else you'd like to know about the weather in New York or any other location?
170
183
  ```
171
184
 
172
185
  ### Step-by-step Breakdown
@@ -175,7 +188,7 @@ Based on the search results, I can tell you that the current weather in New York
175
188
  <summary>Initialize the model and tools.</summary>
176
189
 
177
190
  - We use `ChatAnthropic` as our LLM. **NOTE:** We need make sure the model knows that it has these tools available to call. We can do this by converting the LangChain tools into the format for Anthropic tool calling using the `.bindTools()` method.
178
- - We define the tools we want to use -- a search tool in our case. It is really easy to create your own tools - see documentation [here](https://js.langchain.com/docs/modules/agents/tools/dynamic) on how to do that.
191
+ - We define the tools we want to use -- a weather tool in our case. See the documentation [here](https://js.langchain.com/docs/modules/agents/tools/dynamic) on how to create your own tools.
179
192
  </details>
180
193
 
181
194
  2. <details>
@@ -197,7 +210,7 @@ Based on the search results, I can tell you that the current weather in New York
197
210
  4. <details>
198
211
  <summary>Define entry point and graph edges.</summary>
199
212
 
200
- First, we need to set the entry point for graph execution - `agent` node.
213
+ First, we need to set the entry point for graph execution - the `agent` node.
201
214
 
202
215
  Then we define one normal and one conditional edge. A conditional edge means that the destination depends on the contents of the graph's state (`AgentState`). In our case, the destination is not known until the agent (LLM) decides.
203
216
 
@@ -225,7 +238,7 @@ Based on the search results, I can tell you that the current weather in New York
225
238
  - If `AIMessage` has `tool_calls`, the `"tools"` node executes.
226
239
  - The `"agent"` node executes again and returns an `AIMessage`.
227
240
 
228
- 5. Execution progresses to the special `END` value and outputs the final state.
241
+ 5. Execution progresses to the special `__end__` value and outputs the final state.
229
242
  As a result, we get a list of all our chat messages as output.
230
243
  </details>
231
244
 
@@ -235,3 +248,37 @@ Based on the search results, I can tell you that the current weather in New York
235
248
  - [How-to Guides](https://langchain-ai.github.io/langgraphjs/how-tos/): Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.). These are the place to go if you want to copy and run a specific code snippet.
236
249
  - [Conceptual Guides](https://langchain-ai.github.io/langgraphjs/concepts/): In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more.
237
250
  - [API Reference](https://langchain-ai.github.io/langgraphjs/reference/graphs/): Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more.
251
+
252
+ ## Running Example Juypter Notebooks
253
+
254
+ Please note that the *.ipynb notebooks in the `examples/` folder require [tslab](https://github.com/yunabe/tslab?tab=readme-ov-file) to be installed. In order to run these notebooks in VSCode, you will also need the [Jupyter](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter) VSCode Extension installed. After cloning this repository, you can run `yarn build` in the root. You should then be all set!
255
+
256
+ If you are still having trouble, try adding the following `tsconfig.json` file to the `examples/` directory:
257
+
258
+ ```
259
+ {
260
+ "compilerOptions": {
261
+ "esModuleInterop": true,
262
+ "moduleResolution": "node",
263
+ "target": "ES2020",
264
+ "module": "ES2020",
265
+ "lib": [
266
+ "ES2020"
267
+ ],
268
+ "strict": true,
269
+ "baseUrl": ".",
270
+ "paths": {
271
+ "@langchain/langgraph": [
272
+ "../langgraph/src"
273
+ ]
274
+ }
275
+ },
276
+ "include": [
277
+ "./**/*.ts",
278
+ "./**/*.tsx"
279
+ ],
280
+ "exclude": [
281
+ "node_modules"
282
+ ]
283
+ }
284
+ ```
@@ -5,6 +5,20 @@ const base_js_1 = require("../checkpoint/base.cjs");
5
5
  const id_js_1 = require("../checkpoint/id.cjs");
6
6
  const errors_js_1 = require("../errors.cjs");
7
7
  class BaseChannel {
8
+ constructor() {
9
+ Object.defineProperty(this, "ValueType", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: void 0
14
+ });
15
+ Object.defineProperty(this, "UpdateType", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: void 0
20
+ });
21
+ }
8
22
  }
9
23
  exports.BaseChannel = BaseChannel;
10
24
  function emptyChannels(channels, checkpoint) {
@@ -1,6 +1,8 @@
1
1
  import { ReadonlyCheckpoint } from "../checkpoint/base.js";
2
2
  import { Checkpoint } from "../checkpoint/index.js";
3
3
  export declare abstract class BaseChannel<ValueType = unknown, UpdateType = unknown, CheckpointType = unknown> {
4
+ ValueType: ValueType;
5
+ UpdateType: UpdateType;
4
6
  /**
5
7
  * The name of the channel.
6
8
  */
@@ -2,6 +2,20 @@ import { deepCopy } from "../checkpoint/base.js";
2
2
  import { uuid6 } from "../checkpoint/id.js";
3
3
  import { EmptyChannelError } from "../errors.js";
4
4
  export class BaseChannel {
5
+ constructor() {
6
+ Object.defineProperty(this, "ValueType", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: void 0
11
+ });
12
+ Object.defineProperty(this, "UpdateType", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ }
5
19
  }
6
20
  export function emptyChannels(channels, checkpoint) {
7
21
  const newChannels = {};
@@ -2,7 +2,7 @@ import { BaseMessage, BaseMessageLike } from "@langchain/core/messages";
2
2
  import { StateGraph } from "./state.js";
3
3
  type Messages = Array<BaseMessage | BaseMessageLike> | BaseMessage | BaseMessageLike;
4
4
  export declare function messagesStateReducer(left: Messages, right: Messages): BaseMessage[];
5
- export declare class MessageGraph extends StateGraph<BaseMessage[], Messages> {
5
+ export declare class MessageGraph extends StateGraph<BaseMessage[], BaseMessage[], Messages> {
6
6
  constructor();
7
7
  }
8
8
  export interface MessagesState {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CompiledStateGraph = exports.StateGraph = void 0;
3
+ exports.CompiledStateGraph = exports.StateGraph = exports.Annotation = void 0;
4
4
  const binop_js_1 = require("../channels/binop.cjs");
5
5
  const graph_js_1 = require("./graph.cjs");
6
6
  const last_value_js_1 = require("../channels/last_value.cjs");
@@ -12,6 +12,16 @@ const utils_js_1 = require("../utils.cjs");
12
12
  const constants_js_1 = require("../constants.cjs");
13
13
  const errors_js_1 = require("../errors.cjs");
14
14
  const ROOT = "__root__";
15
+ function Annotation(annotation) {
16
+ if (annotation) {
17
+ return getChannel(annotation);
18
+ }
19
+ else {
20
+ // @ts-expect-error - Annotation without reducer
21
+ return new last_value_js_1.LastValue();
22
+ }
23
+ }
24
+ exports.Annotation = Annotation;
15
25
  class StateGraph extends graph_js_1.Graph {
16
26
  constructor(fields) {
17
27
  super();
@@ -28,7 +38,20 @@ class StateGraph extends graph_js_1.Graph {
28
38
  writable: true,
29
39
  value: new Set()
30
40
  });
31
- this.channels = _getChannels(fields.channels);
41
+ if (isStateDefinition(fields)) {
42
+ this.channels = {};
43
+ for (const [key, val] of Object.entries(fields)) {
44
+ if (typeof val === "function") {
45
+ this.channels[key] = val();
46
+ }
47
+ else {
48
+ this.channels[key] = val;
49
+ }
50
+ }
51
+ }
52
+ else {
53
+ this.channels = _getChannels(fields.channels);
54
+ }
32
55
  for (const c of Object.values(this.channels)) {
33
56
  if (c.lc_graph_name === "BinaryOperatorAggregate") {
34
57
  this.supportMultipleEdges = true;
@@ -147,6 +170,7 @@ function getChannel(reducer) {
147
170
  reducer.value) {
148
171
  return new binop_js_1.BinaryOperatorAggregate(reducer.value, reducer.default);
149
172
  }
173
+ // @ts-expect-error - Annotation without reducer
150
174
  return new last_value_js_1.LastValue();
151
175
  }
152
176
  class CompiledStateGraph extends graph_js_1.CompiledGraph {
@@ -266,3 +290,13 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
266
290
  }
267
291
  }
268
292
  exports.CompiledStateGraph = CompiledStateGraph;
293
+ function isBaseChannel(obj) {
294
+ return obj != null && typeof obj.lc_graph_name === "string";
295
+ }
296
+ function isStateDefinition(obj) {
297
+ return (typeof obj === "object" &&
298
+ obj !== null &&
299
+ !Array.isArray(obj) &&
300
+ Object.keys(obj).length > 0 &&
301
+ Object.values(obj).every((v) => typeof v === "function" || isBaseChannel(v)));
302
+ }
@@ -1,9 +1,23 @@
1
1
  import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
2
2
  import { BaseChannel } from "../channels/base.js";
3
- import { BinaryOperator } from "../channels/binop.js";
3
+ import { BinaryOperator, BinaryOperatorAggregate } from "../channels/binop.js";
4
4
  import { END, CompiledGraph, Graph, START, Branch } from "./graph.js";
5
+ import { LastValue } from "../channels/last_value.js";
5
6
  import { BaseCheckpointSaver } from "../checkpoint/base.js";
6
7
  import { All } from "../pregel/types.js";
8
+ export declare function Annotation<ValueType>(): LastValue<ValueType>;
9
+ export declare function Annotation<ValueType, UpdateType = ValueType>(annotation: SingleReducer<ValueType, UpdateType>): BinaryOperatorAggregate<ValueType, UpdateType>;
10
+ interface StateDefinition {
11
+ [key: string]: BaseChannel | (() => BaseChannel);
12
+ }
13
+ type ExtractValueType<C> = C extends BaseChannel ? C["ValueType"] : C extends () => BaseChannel ? ReturnType<C>["ValueType"] : never;
14
+ type ExtractUpdateType<C> = C extends BaseChannel ? C["UpdateType"] : C extends () => BaseChannel ? ReturnType<C>["UpdateType"] : never;
15
+ export type StateInterface<S extends StateDefinition> = {
16
+ [key in keyof S]: ExtractValueType<S[key]>;
17
+ };
18
+ export type UpdateInterface<S extends StateDefinition> = {
19
+ [key in keyof S]?: ExtractUpdateType<S[key]>;
20
+ };
7
21
  type SingleReducer<ValueType, UpdateType = ValueType> = {
8
22
  reducer: BinaryOperator<ValueType, UpdateType>;
9
23
  default?: () => ValueType;
@@ -24,24 +38,24 @@ export interface StateGraphArgs<Channels extends object | unknown> {
24
38
  __root__: Channels;
25
39
  }>;
26
40
  }
27
- export declare class StateGraph<State extends object | unknown, Update extends object | unknown = Partial<Record<keyof State, any>>, N extends string = typeof START> extends Graph<N, State, Update> {
41
+ export declare class StateGraph<SD extends StateDefinition | unknown, S = SD extends StateDefinition ? StateInterface<SD> : SD, U = SD extends StateDefinition ? UpdateInterface<SD> : Partial<S>, N extends string = typeof START> extends Graph<N, S, U> {
28
42
  channels: Record<string, BaseChannel>;
29
43
  waitingEdges: Set<[N[], N]>;
30
- constructor(fields: StateGraphArgs<State>);
44
+ constructor(fields: SD extends StateDefinition ? SD | StateGraphArgs<S> : StateGraphArgs<S>);
31
45
  get allEdges(): Set<[string, string]>;
32
- addNode<K extends string>(key: K, action: RunnableLike<State, Update>): StateGraph<State, Update, N | K>;
46
+ addNode<K extends string>(key: K, action: RunnableLike<S, U>): StateGraph<SD, S, U, N | K>;
33
47
  addEdge(startKey: typeof START | N | N[], endKey: N | typeof END): this;
34
48
  compile({ checkpointer, interruptBefore, interruptAfter, }?: {
35
49
  checkpointer?: BaseCheckpointSaver;
36
50
  interruptBefore?: N[] | All;
37
51
  interruptAfter?: N[] | All;
38
- }): CompiledStateGraph<State, Update, N>;
52
+ }): CompiledStateGraph<S, U, N>;
39
53
  }
40
- export declare class CompiledStateGraph<State extends object | unknown, Update extends object | unknown = Partial<State>, N extends string = typeof START> extends CompiledGraph<N, State, Update> {
41
- builder: StateGraph<State, Update, N>;
54
+ export declare class CompiledStateGraph<S, U, N extends string = typeof START> extends CompiledGraph<N, S, U> {
55
+ builder: StateGraph<unknown, S, U, N>;
42
56
  attachNode(key: typeof START, node?: never): void;
43
- attachNode(key: N, node: Runnable<State, Update, RunnableConfig>): void;
57
+ attachNode(key: N, node: Runnable<S, U, RunnableConfig>): void;
44
58
  attachEdge(start: N | N[] | "__start__", end: N | "__end__"): void;
45
- attachBranch(start: N | typeof START, name: string, branch: Branch<State, N>): void;
59
+ attachBranch(start: N | typeof START, name: string, branch: Branch<S, N>): void;
46
60
  }
47
61
  export {};
@@ -9,6 +9,15 @@ import { RunnableCallable } from "../utils.js";
9
9
  import { TAG_HIDDEN } from "../constants.js";
10
10
  import { InvalidUpdateError } from "../errors.js";
11
11
  const ROOT = "__root__";
12
+ export function Annotation(annotation) {
13
+ if (annotation) {
14
+ return getChannel(annotation);
15
+ }
16
+ else {
17
+ // @ts-expect-error - Annotation without reducer
18
+ return new LastValue();
19
+ }
20
+ }
12
21
  export class StateGraph extends Graph {
13
22
  constructor(fields) {
14
23
  super();
@@ -25,7 +34,20 @@ export class StateGraph extends Graph {
25
34
  writable: true,
26
35
  value: new Set()
27
36
  });
28
- this.channels = _getChannels(fields.channels);
37
+ if (isStateDefinition(fields)) {
38
+ this.channels = {};
39
+ for (const [key, val] of Object.entries(fields)) {
40
+ if (typeof val === "function") {
41
+ this.channels[key] = val();
42
+ }
43
+ else {
44
+ this.channels[key] = val;
45
+ }
46
+ }
47
+ }
48
+ else {
49
+ this.channels = _getChannels(fields.channels);
50
+ }
29
51
  for (const c of Object.values(this.channels)) {
30
52
  if (c.lc_graph_name === "BinaryOperatorAggregate") {
31
53
  this.supportMultipleEdges = true;
@@ -143,6 +165,7 @@ function getChannel(reducer) {
143
165
  reducer.value) {
144
166
  return new BinaryOperatorAggregate(reducer.value, reducer.default);
145
167
  }
168
+ // @ts-expect-error - Annotation without reducer
146
169
  return new LastValue();
147
170
  }
148
171
  export class CompiledStateGraph extends CompiledGraph {
@@ -261,3 +284,13 @@ export class CompiledStateGraph extends CompiledGraph {
261
284
  }
262
285
  }
263
286
  }
287
+ function isBaseChannel(obj) {
288
+ return obj != null && typeof obj.lc_graph_name === "string";
289
+ }
290
+ function isStateDefinition(obj) {
291
+ return (typeof obj === "object" &&
292
+ obj !== null &&
293
+ !Array.isArray(obj) &&
294
+ Object.keys(obj).length > 0 &&
295
+ Object.values(obj).every((v) => typeof v === "function" || isBaseChannel(v)));
296
+ }
@@ -16,5 +16,5 @@ export interface AgentExecutorState {
16
16
  export declare function createAgentExecutor({ agentRunnable, tools, }: {
17
17
  agentRunnable: Runnable;
18
18
  tools: Array<Tool> | ToolExecutor;
19
- }): import("../graph/state.js").CompiledStateGraph<AgentExecutorState, Partial<Record<keyof AgentExecutorState, any>>, "__start__" | "agent" | "action">;
19
+ }): import("../graph/state.js").CompiledStateGraph<AgentExecutorState, Partial<AgentExecutorState>, "__start__" | "agent" | "action">;
20
20
  export {};
@@ -465,7 +465,7 @@ class Pregel extends runnables_1.Runnable {
465
465
  // execute tasks, and wait for one to fail or all to finish.
466
466
  // each task is independent from all other concurrent tasks
467
467
  const tasks = tasksWithConfig.map(([proc, input, updatedConfig]) => () => proc.invoke(input, updatedConfig));
468
- await executeTasks(tasks, this.stepTimeout);
468
+ await executeTasks(tasks, this.stepTimeout, config.signal);
469
469
  // combine pending writes from all tasks
470
470
  const pendingWrites = [];
471
471
  for (const task of nextTasks) {
@@ -536,28 +536,33 @@ class Pregel extends runnables_1.Runnable {
536
536
  }
537
537
  }
538
538
  exports.Pregel = Pregel;
539
- function timeout(ms) {
540
- return new Promise((reject) => {
541
- setTimeout(reject, ms);
542
- });
543
- }
544
- async function executeTasks(tasks, stepTimeout) {
545
- // Wrap each task in a Promise that respects the step timeout
546
- const wrappedTasks = tasks.map((task) => stepTimeout
547
- ? Promise.race([
548
- task(),
549
- stepTimeout ? timeout(stepTimeout) : Promise.resolve(),
550
- ])
551
- : task());
552
- // Wait for all tasks to settle
553
- const results = await Promise.allSettled(wrappedTasks);
554
- // Process the results
555
- for (const result of results) {
556
- if (result.status === "rejected") {
557
- // If any task failed, cancel all pending tasks and throw the error
558
- throw result.reason;
539
+ async function executeTasks(tasks, stepTimeout, signal) {
540
+ if (stepTimeout && signal) {
541
+ if ("any" in AbortSignal) {
542
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
543
+ signal = AbortSignal.any([
544
+ signal,
545
+ AbortSignal.timeout(stepTimeout),
546
+ ]);
559
547
  }
560
548
  }
549
+ else if (stepTimeout) {
550
+ signal = AbortSignal.timeout(stepTimeout);
551
+ }
552
+ // Abort if signal is aborted
553
+ signal?.throwIfAborted();
554
+ // Start all tasks
555
+ const started = tasks.map((task) => task());
556
+ // Wait for all tasks to settle
557
+ // If any tasks fail, or signal is aborted, the promise will reject
558
+ await Promise.all(signal
559
+ ? [
560
+ ...started,
561
+ new Promise((_resolve, reject) => {
562
+ signal?.addEventListener("abort", () => reject(new Error("Abort")));
563
+ }),
564
+ ]
565
+ : started);
561
566
  }
562
567
  function _shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, tasks) {
563
568
  const anySnapshotChannelUpdated = snapshotChannels.some((chan) => (0, base_js_2.getChannelVersion)(checkpoint, chan) >
@@ -461,7 +461,7 @@ export class Pregel extends Runnable {
461
461
  // execute tasks, and wait for one to fail or all to finish.
462
462
  // each task is independent from all other concurrent tasks
463
463
  const tasks = tasksWithConfig.map(([proc, input, updatedConfig]) => () => proc.invoke(input, updatedConfig));
464
- await executeTasks(tasks, this.stepTimeout);
464
+ await executeTasks(tasks, this.stepTimeout, config.signal);
465
465
  // combine pending writes from all tasks
466
466
  const pendingWrites = [];
467
467
  for (const task of nextTasks) {
@@ -531,28 +531,33 @@ export class Pregel extends Runnable {
531
531
  }
532
532
  }
533
533
  }
534
- function timeout(ms) {
535
- return new Promise((reject) => {
536
- setTimeout(reject, ms);
537
- });
538
- }
539
- async function executeTasks(tasks, stepTimeout) {
540
- // Wrap each task in a Promise that respects the step timeout
541
- const wrappedTasks = tasks.map((task) => stepTimeout
542
- ? Promise.race([
543
- task(),
544
- stepTimeout ? timeout(stepTimeout) : Promise.resolve(),
545
- ])
546
- : task());
547
- // Wait for all tasks to settle
548
- const results = await Promise.allSettled(wrappedTasks);
549
- // Process the results
550
- for (const result of results) {
551
- if (result.status === "rejected") {
552
- // If any task failed, cancel all pending tasks and throw the error
553
- throw result.reason;
534
+ async function executeTasks(tasks, stepTimeout, signal) {
535
+ if (stepTimeout && signal) {
536
+ if ("any" in AbortSignal) {
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ signal = AbortSignal.any([
539
+ signal,
540
+ AbortSignal.timeout(stepTimeout),
541
+ ]);
554
542
  }
555
543
  }
544
+ else if (stepTimeout) {
545
+ signal = AbortSignal.timeout(stepTimeout);
546
+ }
547
+ // Abort if signal is aborted
548
+ signal?.throwIfAborted();
549
+ // Start all tasks
550
+ const started = tasks.map((task) => task());
551
+ // Wait for all tasks to settle
552
+ // If any tasks fail, or signal is aborted, the promise will reject
553
+ await Promise.all(signal
554
+ ? [
555
+ ...started,
556
+ new Promise((_resolve, reject) => {
557
+ signal?.addEventListener("abort", () => reject(new Error("Abort")));
558
+ }),
559
+ ]
560
+ : started);
556
561
  }
557
562
  export function _shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, tasks) {
558
563
  const anySnapshotChannelUpdated = snapshotChannels.some((chan) => getChannelVersion(checkpoint, chan) >