langgraph-middleware 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jake Hon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # langgraph-middleware
2
+
3
+ [![npm version](https://img.shields.io/npm/v/langgraph-middleware.svg)](https://www.npmjs.com/package/langgraph-middleware)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
6
+
7
+ **English** | [中文](doc/README.zh.md)
8
+
9
+ **langgraph-middleware** brings middleware-style utilities to LangGraph's `StateGraph` — add **before/after hooks**, **reusable inject modules**, **error catching**, and **observability callbacks** to your graph nodes with a clean chainable API.
10
+
11
+ ## ✨ Features
12
+
13
+ | Method | Description |
14
+ |--------|-------------|
15
+ | `.middleware(name, before?, after?)` | Wraps a node with **before** / **after** hooks, forming a subgraph <br> Cannot be applied to the same node more than once <br> `before` hook **must not** return a `Command` (use the main node or `after` hook for Command-based routing) |
16
+ | `.inject(...modules)` | Registers reusable structure modules executed before `compile()` |
17
+ | `.observe(callbacks, ...nodes?)` | Attaches LangChain `BaseCallbackHandler` instances for tracing/logging |
18
+ | `.catch(handler, ...nodes?)` | Wraps nodes with try/catch error recovery <br>⚠️ **Do NOT** use on nodes that call `interrupt()` — `GraphInterrupt` will be rejected |
19
+ | `.withNodes(...names)` | Type-level helper to inform TypeScript of dynamically-added node names |
20
+ | `.compileAsync(...)` | Async version of `compile()` — supports async inject modules |
21
+
22
+ - All methods support method chaining
23
+ - Compatible with checkpointing, interrupt, streaming, and retryPolicy
24
+
25
+ ## 📦 Installation
26
+
27
+ ```bash
28
+ npm install langgraph-middleware @langchain/langgraph @langchain/core
29
+ ```
30
+
31
+ ## Use Cases
32
+
33
+ This library is ideal for:
34
+
35
+ - Quickly adding logging, validation, or state transformation before/after specific nodes
36
+ - Reusing the same graph structure across multiple projects (`.inject()`)
37
+ - Attaching tracing / callback handlers to specific nodes (`.observe()`)
38
+ - Rapidly adding/removing nodes and edges without verbose `addNode`/`addEdge` chains (`.inject()`, `.middleware()`)
39
+ - Wrapping a node in a try/catch block for graceful error recovery (`.catch()`)
40
+ - You accept that before/after hooks are implemented as a small internal subgraph (`.middleware()`)
41
+
42
+ ### Not Recommended
43
+
44
+ - Heavy reliance on `.catch()` for error handling — prefer explicit error-handling nodes for complex logic
45
+
46
+ ## 🚀 Quick Start
47
+
48
+ ### Middleware
49
+
50
+ `.middleware()` internally turns your node into a small subgraph (`before_{name}` → `{name}` → `after_{name}`).
51
+
52
+ ```ts
53
+ import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
54
+
55
+ const GraphState = Annotation.Root({
56
+ input: Annotation<string>(),
57
+ logs: Annotation<string[]>({
58
+ reducer: (curr, next) => [...(curr ?? []), ...(next ?? [])],
59
+ default: () => [],
60
+ }),
61
+ });
62
+
63
+ const graph = new StateGraph(GraphState)
64
+ .addNode("process", async (state) => {
65
+ return { result: `done: ${state.input}` };
66
+ })
67
+ .addEdge(START, "process")
68
+ .addEdge("process", END)
69
+ .middleware(
70
+ "process",
71
+ // before hook
72
+ (state) => {
73
+ console.log("before:", state.input);
74
+ return { logs: ["starting"] };
75
+ },
76
+ // after hook
77
+ (state) => {
78
+ console.log("after:", state.result);
79
+ return { logs: ["finished"] };
80
+ }
81
+ )
82
+ .compile();
83
+
84
+ const result = await graph.invoke({ input: "hello" });
85
+ console.log(result);
86
+ ```
87
+
88
+ ### Inject Modules
89
+
90
+ Create reusable modules that modify any graph before compilation:
91
+
92
+ ```ts
93
+ import { StateGraph, Annotation, START, END, type StateGraphWithInject } from "@langchain/langgraph";
94
+
95
+ const MyAnnotation = Annotation.Root({ value: Annotation<string>() });
96
+
97
+ // The second generic parameter tells TypeScript which node names the module adds
98
+ const addLoggingModule = (
99
+ graph: StateGraphWithInject<StateGraph<typeof MyAnnotation>, "logger" | "prepare_logger">
100
+ ) => {
101
+ return graph
102
+ .addNode("prepare_logger", (state) => state)
103
+ .addNode("logger", async (state) => {
104
+ console.log("State:", state);
105
+ return {};
106
+ })
107
+ .addEdge(START, "prepare_logger")
108
+ .addEdge("prepare_logger", "logger");
109
+ };
110
+
111
+ const graph = new StateGraph(MyAnnotation)
112
+ .addNode("main", mainNode)
113
+ .addEdge("logger", "main")
114
+ .addEdge("main", END)
115
+ .inject(addLoggingModule)
116
+ .inject(state => state) // Inline usage
117
+ .inject(moduleA, moduleB, moduleC) // Multiple modules at once
118
+ .compile(); // Use compileAsync() if you injected async modules
119
+ ```
120
+
121
+ > **Important timing note:** `.middleware()`, `.catch()`, and `.observe()` scan nodes at **builder-chain time**. Nodes added via `.inject()` are registered at **compile time** (later). To apply middleware/catch/observe to inject-added nodes, call those methods *inside* the inject module itself. See `examples/inject.ts` for patterns.
122
+
123
+ ### Error Handling
124
+
125
+ ```ts
126
+ const graph = new StateGraph(MyAnnotation)
127
+ .addNode("risky", riskyNode)
128
+ .addEdge(START, "risky")
129
+ .addEdge("risky", END)
130
+ .catch(
131
+ (error, state, meta) => {
132
+ console.error(`Node failed:`, error);
133
+ return { fallback: true, error: String(error) };
134
+ },
135
+ "risky", // Omit to wrap all existing nodes, or list specific ones: "node1", "node2", ...
136
+ )
137
+ .compile();
138
+ ```
139
+
140
+ ### Observability
141
+
142
+ ```ts
143
+ import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
144
+
145
+ class MyTimer extends BaseCallbackHandler {
146
+ name = "MyTimer";
147
+ async handleChainStart(_chain, _inputs, runId, _parentRunId, _tags, _metadata, _runType, name) {
148
+ console.log(`⏱️ [${name}] started`);
149
+ }
150
+ async handleChainEnd(_outputs, runId) {
151
+ console.log(`✅ [${runId.slice(0, 8)}] completed`);
152
+ }
153
+ }
154
+
155
+ const graph = new StateGraph(MyAnnotation)
156
+ .addNode("step1", step1)
157
+ .addNode("step2", step2)
158
+ .addEdge(START, "step1")
159
+ .addEdge("step1", "step2")
160
+ .addEdge("step2", END)
161
+ .observe([new MyTimer()]) // Omitting node names applies to all nodes
162
+ .compile();
163
+ ```
164
+
165
+ ## API Reference
166
+
167
+ ### `.middleware(name, before?, after?, options?)`
168
+
169
+ Attaches before/after hooks around a node. Internally creates a subgraph.
170
+
171
+ **Restrictions:**
172
+ - Called **at most once** per node name (repeated calls throw)
173
+ - `before` function **must not** return a `Command` (throws at runtime)
174
+
175
+ ```ts
176
+ .middleware(
177
+ "myNode",
178
+ (state) => { /* before */ return { logs: ["start"] }; },
179
+ (state) => { /* after */ return { logs: ["end"] }; }
180
+ )
181
+ ```
182
+
183
+ The `after` hook supports `{ func, options }` form for retryPolicy or other node options. The `before` hook also supports this form. An optional 4th argument forwards compile options to the internal subgraph.
184
+
185
+ ### `.inject(...modules)`
186
+
187
+ Registers reusable modules executed in order just before `compile()`. Modules receive the `StateGraph` instance and should return it for chaining.
188
+
189
+ ```ts
190
+ .inject((graph) => {
191
+ return graph
192
+ .addNode("logger", (s) => { console.log(s); return {}; })
193
+ .addEdge(START, "logger");
194
+ })
195
+ ```
196
+
197
+ Supports both sync and async modules. Use `.compileAsync()` when async modules are present — using `.compile()` with async modules throws.
198
+
199
+ ### `.catch(handler, ...names?)`
200
+
201
+ Wraps targeted nodes in try/catch. The handler receives `(error, state, meta)` where `meta` is the `RunnableConfig` (includes `metadata`, `executionInfo`, etc.).
202
+
203
+ - Handler returns a value → the node is treated as successful (short-circuits any remaining retries)
204
+ - Handler throws → the error propagates to LangGraph's normal retryPolicy logic
205
+
206
+ **⚠️ Do NOT use on nodes that call `interrupt()`.** If a `GraphInterrupt` is caught, it is immediately re-thrown as a regular Error to prevent checkpoint corruption.
207
+
208
+ If no node names are provided, all *currently registered* nodes are wrapped.
209
+
210
+ ### `.observe(callbacks, ...names?)`
211
+
212
+ Attaches LangChain `BaseCallbackHandler` instances to nodes. The `runName` in callback events is set to the node name for easy identification in traces.
213
+
214
+ If no node names are provided, all *currently registered* nodes are observed.
215
+
216
+ ### `.withNodes(...names)`
217
+
218
+ A type-level-only helper. Does nothing at runtime — it tells TypeScript that certain node names exist on the builder, enabling type inference after conditional `addNode` calls or `.inject()` usage.
219
+
220
+ ```ts
221
+ const builder = new StateGraph(GraphState)
222
+ .addNode("node1", fn);
223
+
224
+ if (someCondition) {
225
+ builder.addNode("node2", fn).addNode("node3", fn);
226
+ }
227
+
228
+ builder
229
+ .withNodes("node2", "node3") // TypeScript now knows about these
230
+ .addEdge("__start__", "node1")
231
+ .addEdge("node1", "node2")
232
+ .addEdge("node2", "node3");
233
+ ```
234
+
235
+ ### `.compileAsync(...args)`
236
+
237
+ Async version of `compile()`. Awaits all registered inject modules (including async ones) before compilation.
238
+
239
+ ```ts
240
+ const graph = await builder.compileAsync(checkpointerOptions);
241
+ ```
242
+
243
+ ## Examples
244
+
245
+ See the `examples/` directory for runnable demos:
246
+
247
+ | File | Description |
248
+ |------|-------------|
249
+ | `middleware.ts` | Before/after hooks with traceable wrappers and retryPolicy |
250
+ | `middleware-with-checkpointer.ts` | Middleware + checkpoint persistence, xray inspection |
251
+ | `inject.ts` | Async inject modules, conditional edges, error handler injection |
252
+ | `catch.ts` | Error recovery with catch(), multiple target nodes |
253
+ | `catch-with-retry.ts` | catch() + retryPolicy: conditional re-throw pattern |
254
+ | `catch-interrupt-limitation.ts` | Documents the catch + interrupt() incompatibility |
255
+ | `observe.ts` | Callback-based timing/monitoring |
256
+ | `withNodes.ts` | Type-level helper for dynamically-added nodes |
257
+
258
+ Run any example with:
259
+ ```bash
260
+ npx tsx examples/<name>.ts
261
+ ```
262
+
263
+ ## Run Tests
264
+
265
+ All features are verified with comprehensive tests:
266
+
267
+ ```bash
268
+ npm test
269
+ ```
270
+
271
+ ## License
272
+
273
+ MIT © jakehkw
274
+
275
+ ## Links
276
+
277
+ - GitHub: https://github.com/jakehkw/langgraph-middleware
278
+ - npm: https://www.npmjs.com/package/langgraph-middleware
@@ -0,0 +1,22 @@
1
+ import { type StateGraph } from '@langchain/langgraph';
2
+ import type { StateOf } from './types.js';
3
+ /**
4
+ * Wraps one or more nodes with try/catch error handling.
5
+ *
6
+ * When a wrapped node throws, the error handler is invoked with:
7
+ * - `error` — the thrown value
8
+ * - `state` — the state at the time of failure
9
+ * - `meta` — the metadata for the node
10
+ *
11
+ * The handler's return value is used as the node's output, allowing graceful
12
+ * recovery or state mutation on failure.
13
+ *
14
+ * @typeParam T - The `StateGraph` subtype
15
+ * @param this - The `StateGraph` instance
16
+ * @param handler - Error handler receiving (error, state, meta)
17
+ * @param names - Optional list of node names to wrap; if omitted, all nodes
18
+ * @returns `this` for chaining
19
+ * @internal
20
+ */
21
+ export declare function catchError<T extends StateGraph<any>>(this: T, handler: (error: unknown, state: Partial<StateOf<T>>, meta: any) => Partial<StateOf<T>> | Promise<Partial<StateOf<T>>>, ...names: string[]): T;
22
+ //# sourceMappingURL=catch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catch.d.ts","sourceRoot":"","sources":["../src/catch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvE,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AAGvD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,EAClD,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CACP,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE,GAAG,KACN,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EACvD,GAAG,KAAK,EAAE,MAAM,EAAE,KAkDnB"}
package/dist/catch.js ADDED
@@ -0,0 +1,67 @@
1
+ import { GraphInterrupt } from '@langchain/langgraph';
2
+ import { RunnableLambda } from '@langchain/core/runnables';
3
+ import { getNodes } from './utils.js';
4
+ /**
5
+ * Wraps one or more nodes with try/catch error handling.
6
+ *
7
+ * When a wrapped node throws, the error handler is invoked with:
8
+ * - `error` — the thrown value
9
+ * - `state` — the state at the time of failure
10
+ * - `meta` — the metadata for the node
11
+ *
12
+ * The handler's return value is used as the node's output, allowing graceful
13
+ * recovery or state mutation on failure.
14
+ *
15
+ * @typeParam T - The `StateGraph` subtype
16
+ * @param this - The `StateGraph` instance
17
+ * @param handler - Error handler receiving (error, state, meta)
18
+ * @param names - Optional list of node names to wrap; if omitted, all nodes
19
+ * @returns `this` for chaining
20
+ * @internal
21
+ */
22
+ export function catchError(handler, ...names) {
23
+ const nodes = this.nodes;
24
+ const targets = getNodes(names, nodes);
25
+ for (const [nodeName, spec] of Object.entries(targets)) {
26
+ // Design:
27
+ // We always run the original runnable first.
28
+ // If it throws, we immediately give the error to the user's handler.
29
+ //
30
+ // - If handler returns a value → this attempt is treated as success.
31
+ // LangGraph will NOT retry further for this task (even if retries remained).
32
+ // - If handler throws → the error propagates to LangGraph, which will then
33
+ // apply its normal retryPolicy logic for the next attempt (if any remain).
34
+ //
35
+ // Trade-off:
36
+ // This means that for nodes with retryPolicy, using .catch will cause the
37
+ // handler to be invoked on the FIRST error (not only the last).
38
+ // Returning a value from the handler will short-circuit any remaining retries.
39
+ //
40
+ // This is the cleanest and most predictable behavior we can achieve at the
41
+ // current wrapper level while still giving the user powerful control.
42
+ const wrappedRunnable = RunnableLambda.from(async (state, config) => {
43
+ try {
44
+ return await spec.runnable.invoke(state, config);
45
+ }
46
+ catch (err) {
47
+ if (err instanceof GraphInterrupt) {
48
+ throw new Error(`[.catch] Caught a GraphInterrupt in node "${nodeName}".
49
+ This likely means you are using .catch() on a node that calls interrupt(), which is not supported.
50
+ The interrupt will be treated as a normal error and passed to your handler,
51
+ which can lead to unexpected behavior.
52
+ Please remove .catch() from this node or ensure it does not call interrupt().`);
53
+ }
54
+ const result = await Promise.resolve(handler(err, state, config));
55
+ // If the handler itself throws, it will propagate out of this RunnableLambda.
56
+ // LangGraph will then treat it according to its normal error/retry rules.
57
+ return result;
58
+ }
59
+ });
60
+ nodes[nodeName] = {
61
+ ...spec,
62
+ runnable: wrappedRunnable,
63
+ };
64
+ }
65
+ return this;
66
+ }
67
+ //# sourceMappingURL=catch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catch.js","sourceRoot":"","sources":["../src/catch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAExB,OAIuD,EACvD,GAAG,KAAe;IAElB,MAAM,KAAK,GAAI,IAAY,CAAC,KAAoC,CAAC;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAEvC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,UAAU;QACV,6CAA6C;QAC7C,qEAAqE;QACrE,EAAE;QACF,qEAAqE;QACrE,+EAA+E;QAC/E,2EAA2E;QAC3E,6EAA6E;QAC7E,EAAE;QACF,aAAa;QACb,0EAA0E;QAC1E,gEAAgE;QAChE,+EAA+E;QAC/E,EAAE;QACF,2EAA2E;QAC3E,sEAAsE;QACtE,MAAM,eAAe,GAAG,cAAc,CAAC,IAAI,CACzC,KAAK,EAAE,KAAiB,EAAE,MAAY,EAAE,EAAE;YACxC,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;oBAClC,MAAM,IAAI,KAAK,CAAC,6CAA6C,QAAQ;;;;4FAIW,CAAC,CAAC;gBACpF,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;gBAClE,8EAA8E;gBAC9E,0EAA0E;gBAC1E,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC,CACF,CAAC;QAEF,KAAK,CAAC,QAAQ,CAAC,GAAG;YAChB,GAAG,IAAI;YACP,QAAQ,EAAE,eAAe;SAC1B,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import { StateGraph } from '@langchain/langgraph';
2
+ import { getInjectModules } from './inject.js';
3
+ /** Reference to the original `StateGraph.prototype.compile` method. */
4
+ const originalCompile = StateGraph.prototype.compile;
5
+ /**
6
+ * Overrides `StateGraph.prototype.compile` to execute all registered inject
7
+ * modules before the original compilation logic runs.
8
+ *
9
+ * **Important:** Async inject modules are NOT supported here — use
10
+ * `.compileAsync()` for modules that return a `Promise`.
11
+ *
12
+ * @param args - Arguments forwarded to the original `compile()` method
13
+ * @returns A compiled state graph
14
+ * @internal
15
+ */
16
+ StateGraph.prototype.compile = function (...args) {
17
+ const self = this;
18
+ const modules = getInjectModules(self);
19
+ for (const mod of modules) {
20
+ const result = mod(self);
21
+ if (result instanceof Promise) {
22
+ throw new Error('Async module detected in StateGraph.inject(). ' +
23
+ 'Module must be synchronous when using .compile() — ' +
24
+ 'if you need async setup, use .compileAsync() instead.');
25
+ }
26
+ }
27
+ return originalCompile.apply(self, args);
28
+ };
29
+ /**
30
+ * Implementation of `StateGraph.prototype.compileAsync`
31
+ * Execute all registered inject modules (including async ones) before compilation.
32
+ *
33
+ * @param args - Arguments forwarded to the original `compile()` method
34
+ * @returns A Promise resolving to a compiled state graph
35
+ * @internal
36
+ */
37
+ StateGraph.prototype.compileAsync = async function (...args) {
38
+ const self = this;
39
+ const modules = getInjectModules(self);
40
+ for (const mod of modules) {
41
+ await Promise.resolve(mod(self));
42
+ }
43
+ return originalCompile.apply(self, args);
44
+ };
45
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.js","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,uEAAuE;AACvE,MAAM,eAAe,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC;AAErD;;;;;;;;;;GAUG;AACF,UAAU,CAAC,SAAiB,CAAC,OAAO,GAAG,UAAU,GAAG,IAAe;IAClE,MAAM,IAAI,GAAG,IAAW,CAAC;IACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAEvC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,gDAAgD;gBAC9C,qDAAqD;gBACrD,uDAAuD,CAC1D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF;;;;;;;GAOG;AACF,UAAU,CAAC,SAAiB,CAAC,YAAY,GAAG,KAAK,WAAW,GAAG,IAAe;IAC7E,MAAM,IAAI,GAAG,IAAW,CAAC;IACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAEvC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,CAAC,IAAW,EAAE,IAAW,CAAsC,CAAC;AAC9F,CAAC,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * langgraph-middleware
3
+ * ===================
4
+ * Middleware utilities for LangGraph's `StateGraph`.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import type { START, CompiledStateGraph, StateDefinitionInit, ExtractStateType, ExtractUpdateType, StateDefinition, ToStateDefinition, AnyStateSchema } from '@langchain/langgraph';
9
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
10
+ import type { StateOf, NodeNamesOf, ExtractStateGraphModule, LastFunction, StateCallback, MiddleHook } from './types';
11
+ type ExtractStateDefinition<T> = T extends AnyStateSchema ? T : T extends StateDefinitionInit ? ToStateDefinition<T> : StateDefinition;
12
+ declare module '@langchain/langgraph' {
13
+ type StateGraphWithInject<T, NewNodes extends string | readonly string[] = typeof START> = T extends StateGraph<infer A, infer B, infer C, infer Node, infer D, infer E, infer F, infer G, infer H, infer I> ? StateGraph<A, B, C, Node | (NewNodes extends readonly string[] ? NewNodes[number] : NewNodes), D, E, F, G, H, I> : never;
14
+ interface StateGraph<SD extends StateDefinitionInit | unknown, S = ExtractStateType<SD>, U = ExtractUpdateType<SD, S>, N extends string = typeof START, I extends StateDefinitionInit = ExtractStateDefinition<SD>, O extends StateDefinitionInit = ExtractStateDefinition<SD>, C extends StateDefinitionInit = StateDefinition, NodeReturnType = unknown, InterruptType = unknown, WriterType = unknown> {
15
+ /**
16
+ * Implementation of `StateGraph.prototype.inject`.
17
+ *
18
+ * Registers one or more functions that will be executed in order before the graph is compiled.
19
+ * Supports method chaining.
20
+ * @param modules - One or more inject modules containing the graph instance in its param.
21
+ * @returns `this` for chaining
22
+ */
23
+ inject<T extends ((p: this) => this)[]>(...modules: T): this;
24
+ inject<T extends any[], U extends ExtractStateGraphModule<LastFunction<T[number]>>, const Nodes extends NodeNamesOf<Parameters<U>[0]>>(...modules: T): StateGraphWithInject<StateGraph<SD, S, ExtractUpdateType<SD, S>, NodeNamesOf<this> | N, ExtractStateDefinition<SD>, ExtractStateDefinition<SD>, StateDefinition, unknown, unknown, unknown>, Nodes>;
25
+ /**
26
+ * Wraps one or more nodes with try/catch error handling.
27
+ *
28
+ * When a wrapped node throws, the error handler is invoked with:
29
+ * - `error` — the thrown value
30
+ * - `state` — the state at the time of failure
31
+ * - `meta` — the RunnableConfig (with metadata, executionInfo, etc.)
32
+ *
33
+ * The handler's return value is used as the node's output, allowing graceful
34
+ * recovery or state mutation on failure.
35
+ *
36
+ * ⚠️ IMPORTANT RESTRICTION:
37
+ * You **cannot** use `.catch()` on nodes that may call `interrupt()`.
38
+ * If `GraphInterrupt` is caught, it is immediately re-thrown as a regular
39
+ * Error to prevent silent checkpoint corruption. The handler will NOT receive it.
40
+ *
41
+ * @param handler - Error handler receiving (error, state, meta)
42
+ * @param names - Optional list of node names to wrap; if omitted, all existing nodes
43
+ * @returns `this` for chaining
44
+ */
45
+ catch(handler: (error: any, state: Partial<StateOf<this>>, meta: any) => Partial<StateOf<this>> | Promise<Partial<StateOf<this>>>, ...names: NodeNamesOf<this>[]): this;
46
+ /**
47
+ * Attaches LangChain callback handlers to one or more nodes for
48
+ * observability (logging, tracing, monitoring).
49
+ *
50
+ * Each targeted node is wrapped so that its execution is reported through
51
+ * the provided callbacks. The `runName` in callback events is set to the
52
+ * node name for easy identification.
53
+ *
54
+ * @param callbacks - Array of callback handlers to attach
55
+ * @param names - Optional list of node names to observe; if omitted, all nodes
56
+ * @returns `this` for chaining
57
+ */
58
+ observe(callbacks: BaseCallbackHandler[], ...names: NodeNamesOf<this>[]): this;
59
+ /**
60
+ * Attach before/after hooks around a node.
61
+ *
62
+ * Restrictions (enforced):
63
+ * - You may call .middleware() **at most once** per node name on a given builder.
64
+ * Nested / repeated calls on the same node are rejected (prevents non-linear execution and
65
+ * exponential before-hook duplication that occurs with deep nesting).
66
+ * - The `before` function **must not** return a `Command`. Doing so will throw at runtime.
67
+ * Use the main node or the `after` hook for any Command-based routing.
68
+ *
69
+ * @param name - Name of a previously registered node
70
+ * @param before - Optional before hook (plain function or { func, options })
71
+ * @param after - Optional after hook (plain function or { func, options })
72
+ * @param options - Compile options for the internal subgraph (advanced)
73
+ * @returns `this` for chaining
74
+ */
75
+ middleware<T = MiddleHook<StateCallback<StateOf<this>>, StateOf<this>>, U = T, V = T>(name: NodeNamesOf<this>, before?: U, after?: V, options?: Parameters<this['compile']>[0]): this;
76
+ /**
77
+ * Implementation of `StateGraph.prototype.compileAsync`
78
+ * Execute all registered inject modules (including async ones) before compilation.
79
+ *
80
+ * @param args - Arguments forwarded to the original `compile()` method
81
+ * @returns A Promise resolving to a compiled state graph
82
+ */
83
+ compileAsync(...args: any[]): Promise<CompiledStateGraph<any, any, any>>;
84
+ /**
85
+ * A type-level only chain method to explicitly tell TypeScript
86
+ * that certain node names now exist on this builder.
87
+ *
88
+ * This is useful after .inject() or stepwise .addNode() calls,
89
+ * where the variable's static type hasn't automatically picked up
90
+ * the newly added nodes.
91
+ *
92
+ * Example:
93
+ * const b = new StateGraph(GraphState)
94
+ * .inject(addTimestampModule)
95
+ * .withNodes<'timestamp'>();
96
+ *
97
+ * After this, NodeNamesOf<typeof b> will include "timestamp".
98
+ */
99
+ withNodes<Nodes extends string[]>(...names: Nodes): StateGraphWithInject<StateGraph<SD, S, ExtractUpdateType<SD, S>, NodeNamesOf<this>, ExtractStateDefinition<SD>, ExtractStateDefinition<SD>, StateDefinition, unknown, unknown, unknown>, Nodes>;
100
+ }
101
+ }
102
+ import './compile.js';
103
+ export type { StateOf, NodeNamesOf } from './types.js';
104
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * langgraph-middleware
3
+ * ===================
4
+ * Middleware utilities for LangGraph's `StateGraph`.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
9
+ // ═══════════════════════════════════════════════════════════════════════
10
+ // Apply prototype augmentations (side effects)
11
+ // ═══════════════════════════════════════════════════════════════════════
12
+ import { StateGraph } from '@langchain/langgraph';
13
+ import './compile.js';
14
+ import { inject } from './inject.js';
15
+ import { middleware } from './middleware.js';
16
+ import { catchError } from './catch.js';
17
+ import { observe } from './observe.js';
18
+ import { withNodes } from './withNodes';
19
+ const proto = StateGraph.prototype;
20
+ if (!Object.prototype.hasOwnProperty.call(proto, 'inject')) {
21
+ proto.inject = inject;
22
+ }
23
+ if (!Object.prototype.hasOwnProperty.call(proto, 'middleware')) {
24
+ proto.middleware = middleware;
25
+ }
26
+ if (!Object.prototype.hasOwnProperty.call(proto, 'catch')) {
27
+ proto.catch = catchError;
28
+ }
29
+ if (!Object.prototype.hasOwnProperty.call(proto, 'observe')) {
30
+ proto.observe = observe;
31
+ }
32
+ if (!Object.prototype.hasOwnProperty.call(proto, 'withNodes')) {
33
+ proto.withNodes = withNodes;
34
+ }
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAiJrE,0EAA0E;AAC1E,+CAA+C;AAC/C,0EAA0E;AAE1E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,KAAK,GAAG,UAAU,CAAC,SAAgB,CAAC;AAE1C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;IAC3D,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;AACxB,CAAC;AACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC;IAC/D,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC;AAChC,CAAC;AACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;IAC1D,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC;AAC3B,CAAC;AACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC5D,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;AAC1B,CAAC;AACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;IAC9D,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { StateGraph } from '@langchain/langgraph';
2
+ type Graph = StateGraph<any>;
3
+ /**
4
+ * Retrieves (or creates) the inject-module queue for a given `StateGraph`
5
+ * instance.
6
+ * @internal
7
+ */
8
+ export declare function getInjectModules(graph: Graph): ((...p: any) => any)[];
9
+ /**
10
+ * Implementation of `StateGraph.prototype.inject`.
11
+ *
12
+ * Registers one or more functions that will be executed in order before the graph is compiled.
13
+ * Supports method chaining.
14
+ *
15
+ * @param this - The `StateGraph` instance
16
+ * @param modules - One or more inject modules
17
+ * @returns `this` for chaining
18
+ * @internal
19
+ */
20
+ export declare function inject(this: Graph, ...modules: ((...p: any) => any)[]): Graph;
21
+ export {};
22
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,KAAK,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;AAU5B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,GACX,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,EAAE,CAOxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,KAAK,EACX,GAAG,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,EAAE,SAKnC"}
package/dist/inject.js ADDED
@@ -0,0 +1,34 @@
1
+ // ── Per-graph inject module queue ─────────────────────────────────────
2
+ // We use a WeakMap keyed on each StateGraph instance so that modules are
3
+ // garbage-collected when the graph is no longer referenced.
4
+ const modulesMap = new WeakMap();
5
+ /**
6
+ * Retrieves (or creates) the inject-module queue for a given `StateGraph`
7
+ * instance.
8
+ * @internal
9
+ */
10
+ export function getInjectModules(graph) {
11
+ let list = modulesMap.get(graph);
12
+ if (!list) {
13
+ list = [];
14
+ modulesMap.set(graph, list);
15
+ }
16
+ return list;
17
+ }
18
+ /**
19
+ * Implementation of `StateGraph.prototype.inject`.
20
+ *
21
+ * Registers one or more functions that will be executed in order before the graph is compiled.
22
+ * Supports method chaining.
23
+ *
24
+ * @param this - The `StateGraph` instance
25
+ * @param modules - One or more inject modules
26
+ * @returns `this` for chaining
27
+ * @internal
28
+ */
29
+ export function inject(...modules) {
30
+ const list = getInjectModules(this);
31
+ list.push(...modules);
32
+ return this;
33
+ }
34
+ //# sourceMappingURL=inject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.js","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"AAIA,yEAAyE;AACzE,yEAAyE;AACzE,4DAA4D;AAC5D,MAAM,UAAU,GAAG,IAAI,OAAO,EAG3B,CAAC;AAEJ;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAY;IAEZ,IAAI,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,EAAE,CAAC;QACV,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,MAAM,CAEpB,GAAG,OAA+B;IAElC,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { StateGraph } from '@langchain/langgraph';
2
+ import type { MiddleHook, StateCallback, StateOf } from './types';
3
+ /**
4
+ * Attach before/after hooks around a node.
5
+ *
6
+ * Restrictions (enforced):
7
+ * - You may call .middleware() **at most once** per node name on a given builder.
8
+ * Nested / repeated calls on the same node are rejected (prevents non-linear execution and
9
+ * exponential before-hook duplication that occurs with deep nesting).
10
+ * - The `before` function **must not** return a `Command`. Doing so will throw at runtime.
11
+ * Use the main node or the `after` hook for any Command-based routing.
12
+ *
13
+ * @typeParam T - The `StateGraph` subtype
14
+ * @param this - The `StateGraph` instance
15
+ * @param name - Name of a previously registered node
16
+ * @param before - Hook executed before the original node (optional)
17
+ * @param after - Hook executed after the original node (optional)
18
+ * @param options - Compile options for the internal subgraph (advanced)
19
+ * @returns `this` for chaining
20
+ * @internal
21
+ */
22
+ export declare function middleware<T extends StateGraph<any>>(this: T, name: string, before?: MiddleHook<StateCallback<StateOf<T>>, StateOf<T>>, after?: MiddleHook<StateCallback<StateOf<T>>, StateOf<T>>, options?: Parameters<T['compile']>[0]): T;
23
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAA4B,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAalE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,EAClD,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAC1D,KAAK,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EACzD,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAmEtC"}
@@ -0,0 +1,81 @@
1
+ import { END, START, StateGraph, isCommand } from '@langchain/langgraph';
2
+ const MIDDLEWARE_WRAPPED = Symbol('middlewareWrapped');
3
+ const extract = (par) => {
4
+ if (typeof par === 'function') {
5
+ return { func: par, options: {} };
6
+ }
7
+ return { func: par.func, options: par.options ?? {} };
8
+ };
9
+ /**
10
+ * Attach before/after hooks around a node.
11
+ *
12
+ * Restrictions (enforced):
13
+ * - You may call .middleware() **at most once** per node name on a given builder.
14
+ * Nested / repeated calls on the same node are rejected (prevents non-linear execution and
15
+ * exponential before-hook duplication that occurs with deep nesting).
16
+ * - The `before` function **must not** return a `Command`. Doing so will throw at runtime.
17
+ * Use the main node or the `after` hook for any Command-based routing.
18
+ *
19
+ * @typeParam T - The `StateGraph` subtype
20
+ * @param this - The `StateGraph` instance
21
+ * @param name - Name of a previously registered node
22
+ * @param before - Hook executed before the original node (optional)
23
+ * @param after - Hook executed after the original node (optional)
24
+ * @param options - Compile options for the internal subgraph (advanced)
25
+ * @returns `this` for chaining
26
+ * @internal
27
+ */
28
+ export function middleware(name, before, after, options) {
29
+ const nodes = this.nodes;
30
+ const nodeSpec = nodes[name];
31
+ if (!nodeSpec) {
32
+ throw new Error(`Node "${name}" does not exist on this graph. ` +
33
+ `Register it first with .addNode("${name}", ...)`);
34
+ }
35
+ // Block nested middleware on the same node (prevents exponential before-hook duplication)
36
+ if (nodeSpec[MIDDLEWARE_WRAPPED]) {
37
+ throw new Error(`Cannot apply .middleware() to node "${name}" — it has already been wrapped by a previous .middleware() call.\n` +
38
+ 'Nested middleware on the same node is not supported.\n' +
39
+ 'If you need multiple before/after stages, compose the logic inside a single .middleware() call or use explicit nodes + edges instead.');
40
+ }
41
+ const subGraph = new StateGraph(this.channels).addNode(name, nodeSpec.runnable);
42
+ if (before) {
43
+ const { func, options: nodeOptions } = extract(before);
44
+ // Guard: Before hooks must never return Command (leads to surprising non-native behavior)
45
+ const guardedBefore = async (state, config) => {
46
+ const result = await Promise.resolve(func(state, config));
47
+ if (isCommand(result)) {
48
+ throw new Error(`Before hooks passed to .middleware("${name}", beforeFn, ...) are not allowed to return Command objects.\n` +
49
+ 'Returning Command from a before hook does not behave reliably (the original node may still execute).\n' +
50
+ 'Please perform routing with Command from the main node function or the after hook instead.');
51
+ }
52
+ return result;
53
+ };
54
+ subGraph
55
+ .addNode('before_' + name, guardedBefore, nodeOptions)
56
+ .addEdge(START, 'before_' + name)
57
+ .addEdge('before_' + name, name);
58
+ }
59
+ else {
60
+ subGraph.addEdge(START, name);
61
+ }
62
+ if (after) {
63
+ const { func, options: nodeOptions } = extract(after);
64
+ subGraph
65
+ .addNode('after_' + name, func, nodeOptions)
66
+ .addEdge(name, 'after_' + name)
67
+ .addEdge('after_' + name, END);
68
+ }
69
+ else {
70
+ subGraph.addEdge(name, END);
71
+ }
72
+ delete nodes[name];
73
+ this.addNode(name, subGraph.compile(options));
74
+ // Mark the newly wrapped node so future .middleware() calls on it are rejected
75
+ const newSpec = nodes[name];
76
+ if (newSpec) {
77
+ newSpec[MIDDLEWARE_WRAPPED] = true;
78
+ }
79
+ return this;
80
+ }
81
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { StateGraph } from '@langchain/langgraph';
2
+ import type { BaseCallbackHandler } from '@langchain/core/callbacks/base';
3
+ /**
4
+ * Attaches LangChain callback handlers to one or more nodes for
5
+ * observability (logging, tracing, monitoring).
6
+ *
7
+ * Each targeted node is wrapped so that its execution is reported through
8
+ * the provided callbacks. The `runName` in callback events is set to the
9
+ * node name for easy identification.
10
+ *
11
+ * @typeParam T - The `StateGraph` subtype
12
+ * @param this - The `StateGraph` instance
13
+ * @param callbacks - Array of callback handlers to attach
14
+ * @param names - Optional list of node names to observe; if omitted, all nodes
15
+ * @returns `this` for chaining
16
+ * @internal
17
+ */
18
+ export declare function observe<T extends StateGraph<any>>(this: T, callbacks: BaseCallbackHandler[], ...names: string[]): T;
19
+ //# sourceMappingURL=observe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,sBAAsB,CAAC;AAGjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAM1E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,EAC/C,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,mBAAmB,EAAE,EAChC,GAAG,KAAK,EAAE,MAAM,EAAE,KAqBnB"}
@@ -0,0 +1,33 @@
1
+ import { RunnableLambda } from '@langchain/core/runnables';
2
+ import { getNodes } from './utils.js';
3
+ /**
4
+ * Attaches LangChain callback handlers to one or more nodes for
5
+ * observability (logging, tracing, monitoring).
6
+ *
7
+ * Each targeted node is wrapped so that its execution is reported through
8
+ * the provided callbacks. The `runName` in callback events is set to the
9
+ * node name for easy identification.
10
+ *
11
+ * @typeParam T - The `StateGraph` subtype
12
+ * @param this - The `StateGraph` instance
13
+ * @param callbacks - Array of callback handlers to attach
14
+ * @param names - Optional list of node names to observe; if omitted, all nodes
15
+ * @returns `this` for chaining
16
+ * @internal
17
+ */
18
+ export function observe(callbacks, ...names) {
19
+ const nodes = this.nodes;
20
+ const targets = getNodes(names, nodes);
21
+ for (const [nodeName, spec] of Object.entries(targets)) {
22
+ const wrappedRunnable = RunnableLambda.from(async (state, config) => spec.runnable.invoke(state, config)).withConfig({
23
+ callbacks,
24
+ runName: nodeName,
25
+ });
26
+ nodes[nodeName] = {
27
+ ...spec,
28
+ runnable: wrappedRunnable,
29
+ };
30
+ }
31
+ return this;
32
+ }
33
+ //# sourceMappingURL=observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.js","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,OAAO,CAErB,SAAgC,EAChC,GAAG,KAAe;IAElB,MAAM,KAAK,GAAI,IAAY,CAAC,KAAoC,CAAC;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAEvC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,MAAM,eAAe,GAAG,cAAc,CAAC,IAAI,CACzC,KAAK,EAAE,KAAiB,EAAE,MAAuB,EAAE,EAAE,CACnD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CACtC,CAAC,UAAU,CAAC;YACX,SAAS;YACT,OAAO,EAAE,QAAQ;SAClB,CAAC,CAAC;QAEH,KAAK,CAAC,QAAQ,CAAC,GAAG;YAChB,GAAG,IAAI;YACP,QAAQ,EAAE,eAAe;SAC1B,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { END, NodeSpec, START, StateGraph, StateGraphAddNodeOptions } from '@langchain/langgraph';
2
+ import type { TraceableFunction } from 'langsmith/traceable';
3
+ /**
4
+ * Extract all states from StateGraph
5
+ */
6
+ export type StateOf<T> = T extends StateGraph<any, infer S, any, any, any, any, any, any, any, any> ? S : never;
7
+ /**
8
+ * Extract all node names from StateGraph (exclude START / END)
9
+ */
10
+ export type NodeNamesOf<T> = T extends StateGraph<any, any, any, infer N, any, any, any, any, any, any> ? Exclude<N, typeof START | typeof END> : never;
11
+ /**
12
+ * Unwrap traceable-wrapped functions to their inner type.
13
+ * Extensible for other wrapper types as needed.
14
+ */
15
+ type ExtractFrom<T> = T extends TraceableFunction<infer A> ? A : T;
16
+ type IsStateGraph<T> = T extends Promise<StateGraph<any, any, any, any>> | StateGraph<any, any, any, any> ? true : false;
17
+ export type ExtractStateGraphModule<T> = T extends IsStateGraph<T> ? (p: T) => T : T extends (...args: any) => infer R ? IsStateGraph<R> extends true ? T : never : never;
18
+ export type StateCallback<T> = (p: T) => Partial<T>;
19
+ export type MiddleHookFunc<T, U> = ExtractFrom<T> extends StateCallback<U> ? T : T extends (...args: any) => infer R ? MiddleHookFunc<R, U> : never;
20
+ export type MiddleHook<T, U> = MiddleHookFunc<T, U> | {
21
+ func: MiddleHookFunc<T, U>;
22
+ options?: StateGraphAddNodeOptions;
23
+ };
24
+ export type LastFunction<T> = T extends (...args: any) => infer R ? R extends Promise<infer P> ? P extends (...args: any) => any ? LastFunction<P> : ExtractFrom<T> : R extends AsyncIterable<infer Item> ? LastFunction<Item> : R extends (...args: any) => any ? LastFunction<R> : ExtractFrom<T> : never;
25
+ export type AnyNodeSpec = NodeSpec<any, any> & StateGraphAddNodeOptions;
26
+ export {};
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAC3C,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CACrD,GACG,CAAC,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAC/C,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CACrD,GACG,OAAO,CAAC,CAAC,EAAE,OAAO,KAAK,GAAG,OAAO,GAAG,CAAC,GACrC,KAAK,CAAC;AAEV;;;GAGG;AACH,KAAK,WAAW,CAAC,CAAC,IAChB,CAAC,SAAS,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAChC,CAAC,GACD,CAAC,CAAC;AAER,KAAK,YAAY,CAAC,CAAC,IACjB,CAAC,SAAS,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAC9E,IAAI,GACJ,KAAK,CAAC;AAEZ,MAAM,MAAM,uBAAuB,CAAC,CAAC,IACnC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GACnC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GACtE,KAAK,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpD,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,IAC7B,WAAW,CAAC,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,GACnC,CAAC,GACD,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,GACjC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GACpB,KAAK,CAAC;AAEd,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IACpD,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACpC,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IACxB,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,GAC/B,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GACxB,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAC7B,YAAY,CAAC,CAAC,CAAC,GACf,WAAW,CAAC,CAAC,CAAC,GAChB,CAAC,SAAS,aAAa,CAAC,MAAM,IAAI,CAAC,GACjC,YAAY,CAAC,IAAI,CAAC,GAClB,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAC7B,YAAY,CAAC,CAAC,CAAC,GACf,WAAW,CAAC,CAAC,CAAC,GACpB,KAAK,CAAC;AAEZ,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,wBAAwB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import type { AnyNodeSpec } from './types';
2
+ /**
3
+ * Filters the graph's node registry to only include the specified node names.
4
+ *
5
+ * If no names are provided, the entire node registry is returned as-is.
6
+ * This is used internally by `catch()` and `observe()` to optionally scope
7
+ * their effects to a subset of nodes.
8
+ *
9
+ * @param names - Specific node names to select, or an empty array for all nodes
10
+ * @param nodes - The full node registry from `StateGraph.nodes`
11
+ * @returns A filtered copy of the node registry
12
+ * @internal
13
+ */
14
+ export declare function getNodes(names: string[], nodes: Record<string, AnyNodeSpec>): Record<string, AnyNodeSpec>;
15
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAe7B"}
package/dist/utils.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Filters the graph's node registry to only include the specified node names.
3
+ *
4
+ * If no names are provided, the entire node registry is returned as-is.
5
+ * This is used internally by `catch()` and `observe()` to optionally scope
6
+ * their effects to a subset of nodes.
7
+ *
8
+ * @param names - Specific node names to select, or an empty array for all nodes
9
+ * @param nodes - The full node registry from `StateGraph.nodes`
10
+ * @returns A filtered copy of the node registry
11
+ * @internal
12
+ */
13
+ export function getNodes(names, nodes) {
14
+ if (!names || names.length === 0) {
15
+ return nodes;
16
+ }
17
+ const targetNames = new Set(names);
18
+ const result = {};
19
+ for (const key of Object.keys(nodes)) {
20
+ if (targetNames.has(key)) {
21
+ result[key] = nodes[key];
22
+ }
23
+ }
24
+ return result;
25
+ }
26
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAe,EACf,KAAkC;IAElC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,MAAM,GAAgC,EAAE,CAAC;IAE/C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Runtime implementation for the new type-level helper method.
3
+ * It does nothing at runtime — its only purpose is to help TypeScript
4
+ * narrow the 4th generic (N) through the return type.
5
+ *
6
+ * @returns `this` for chaining
7
+ * @internal
8
+ */
9
+ export declare function withNodes(this: any): any;
10
+ //# sourceMappingURL=withNodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withNodes.d.ts","sourceRoot":"","sources":["../src/withNodes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,OAElC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Runtime implementation for the new type-level helper method.
3
+ * It does nothing at runtime — its only purpose is to help TypeScript
4
+ * narrow the 4th generic (N) through the return type.
5
+ *
6
+ * @returns `this` for chaining
7
+ * @internal
8
+ */
9
+ export function withNodes() {
10
+ return this;
11
+ }
12
+ //# sourceMappingURL=withNodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withNodes.js","sourceRoot":"","sources":["../src/withNodes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "langgraph-middleware",
3
+ "version": "1.0.0",
4
+ "description": "Middleware utilities for LangGraph StateGraph — inject modules, before/after hooks, error catching, and callback observation",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "lint": "eslint .",
23
+ "lint:fix": "eslint . --fix",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest watch",
26
+ "test:coverage": "vitest run --coverage",
27
+ "prepublishOnly": "npm run build && npm run test"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/jakehkw/langgraph-middleware.git"
32
+ },
33
+ "keywords": [
34
+ "langgraph",
35
+ "langchain",
36
+ "middleware",
37
+ "state-graph",
38
+ "hooks",
39
+ "inject",
40
+ "catch",
41
+ "observe",
42
+ "before-after",
43
+ "llm",
44
+ "ai"
45
+ ],
46
+ "author": "jakehkw",
47
+ "license": "MIT",
48
+ "bugs": {
49
+ "url": "https://github.com/jakehkw/langgraph-middleware/issues"
50
+ },
51
+ "homepage": "https://github.com/jakehkw/langgraph-middleware#readme",
52
+ "peerDependencies": {
53
+ "langsmith": "^0.7.3",
54
+ "@langchain/core": "^1.0.0",
55
+ "@langchain/langgraph": "^1.0.0"
56
+ },
57
+ "peerDependenciesMeta": {
58
+ "@langchain/core": {
59
+ "optional": false
60
+ },
61
+ "@langchain/langgraph": {
62
+ "optional": false
63
+ },
64
+ "langsmith": {
65
+ "optional": true
66
+ }
67
+ },
68
+ "devDependencies": {
69
+ "@langchain/core": "^1.1.47",
70
+ "@langchain/langgraph": "^1.3.2",
71
+ "@types/node": "25.9.1",
72
+ "eslint": "^10.4.0",
73
+ "globals": "^17.6.0",
74
+ "langsmith": "^0.7.3",
75
+ "typescript": "^6.0.3",
76
+ "typescript-eslint": "^8.59.4",
77
+ "vitest": "4.1.7"
78
+ },
79
+ "engines": {
80
+ "node": ">=18"
81
+ }
82
+ }