[PR #112] [CLOSED] Add a graph builder #499

Closed
opened 2026-02-15 18:17:11 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/langchain-ai/langgraphjs/pull/112
Author: @functorism
Created: 4/6/2024
Status: Closed

Base: mainHead: graph-builder


📝 Commits (1)

📊 Changes

2 files changed (+465 additions, -0 deletions)

View changed files

langgraph/src/graph/builder.ts (+252 -0)
langgraph/src/tests/graph-builder.test.ts (+213 -0)

📄 Description

This PR shows one possible way to construct a graph builder.

This graph builder turns what is now run-time errors during graph construction into type-errors. Meaning users get the same error feedback directly in their IDE as type errors without having to run the code. There is also the added benefit that they get some level of "intellisense" while writing the code.

The builder has the same API as Graph, with the addition of a .done() method and stricter input types.

One can peruse the test file for examples of how to use the builder and what type of errors it catches at "compile-time".

The builder works via the fact that methods return the this instance with additional type information:

  // Adds a node to the graph and returns a builder that's aware of that nodes existence
  addNode<K extends string>(
    this: GraphBuilder<RunInput, RunOutput, Nodes>,
    key: K,
    action: RunnableLike<RunInput, RunOutput>
  ): GraphBuilder<RunInput, RunOutput, Nodes | K> {
    super.addNode(key, action);
    return this;
  }

Which allows us to catch simple mistakes like:

new GraphBuilder()
  .addNode("a", () => {})
  .addNode("b", () => {})
  // This is fine
  .addEdge("a", "b")
  // @ts-expect-error - this must type-error
  .addEdge("b", "c");
new GraphBuilder()
  .addNode("a", () => {})
  .addNode("b", () => {})
  .addConditionalEdges("b", () => "next", {
    continue: "b",
 // ^^^^^^^^ - The type error will be localized here
 // Error: Object literal may only specify known properties,
 // and 'continue' does not exist in type 'Record<"next", "b">'
  });

The builder doesn't guarantee perfect safety due to limitations of what TypeScript's type system can express; but it does make it a lot easier to do the right thing.

A clear example of these limitations is that we have no way to "invalidate" references to "old" builder instances; if one creates "forks" of the builder, you'll run into unexpected behavior.

The code duplication for GraphBuilder and StateGraphBuilder is inelegant, but can be improved if this idea is deemed appealing!

Having access to a graph builder that provides "at construction time checking" sweetens the deal if one would want to move the runtime checks that exists in Graph into the compile function entirely. As suggested in this issue https://github.com/langchain-ai/langgraphjs/issues/88. If construction time checking is a type-level concern and compile time checking a runtime one; then it's possible to support both use cases. Making it possible to support construction methods that only have to be valid at compile time - then order of node and edge inserts does not matter. It only matters that the state is correct when calling compile. And for those wanting construction time validation (and "intellisense"), then the builder is available.

Thanks @davidfant for reviewing and helping to find a bug prior to opening this.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/langchain-ai/langgraphjs/pull/112 **Author:** [@functorism](https://github.com/functorism) **Created:** 4/6/2024 **Status:** ❌ Closed **Base:** `main` ← **Head:** `graph-builder` --- ### 📝 Commits (1) - [`e82dbd8`](https://github.com/langchain-ai/langgraphjs/commit/e82dbd86dec40c0c19e4636960bd290452de92e3) Add a graph builder ### 📊 Changes **2 files changed** (+465 additions, -0 deletions) <details> <summary>View changed files</summary> ➕ `langgraph/src/graph/builder.ts` (+252 -0) ➕ `langgraph/src/tests/graph-builder.test.ts` (+213 -0) </details> ### 📄 Description This PR shows one possible way to construct a graph builder. This graph builder turns what is now run-time errors during graph construction into type-errors. Meaning users get the same error feedback directly in their IDE as type errors without having to run the code. There is also the added benefit that they get some level of "intellisense" while writing the code. The builder has the same API as `Graph`, with the addition of a `.done()` method and stricter input types. One can peruse the [test file](https://github.com/functorism/langgraphjs/blob/graph-builder/langgraph/src/tests/graph-builder.test.ts) for examples of how to use the builder and what type of errors it catches at "compile-time". The builder works via the fact that methods return the `this` instance with additional type information: ```typescript // Adds a node to the graph and returns a builder that's aware of that nodes existence addNode<K extends string>( this: GraphBuilder<RunInput, RunOutput, Nodes>, key: K, action: RunnableLike<RunInput, RunOutput> ): GraphBuilder<RunInput, RunOutput, Nodes | K> { super.addNode(key, action); return this; } ``` Which allows us to catch simple mistakes like: ```typescript new GraphBuilder() .addNode("a", () => {}) .addNode("b", () => {}) // This is fine .addEdge("a", "b") // @ts-expect-error - this must type-error .addEdge("b", "c"); ``` ```typescript new GraphBuilder() .addNode("a", () => {}) .addNode("b", () => {}) .addConditionalEdges("b", () => "next", { continue: "b", // ^^^^^^^^ - The type error will be localized here // Error: Object literal may only specify known properties, // and 'continue' does not exist in type 'Record<"next", "b">' }); ``` The builder doesn't guarantee perfect safety due to limitations of what TypeScript's type system can express; but it does make it a lot easier to _do the right thing_. A clear example of these limitations is that we have no way to "invalidate" references to "old" builder instances; if one creates ["forks" of the builder](https://github.com/functorism/langgraphjs/blob/graph-builder/langgraph/src/tests/graph-builder.test.ts#L77-L90), you'll run into unexpected behavior. The code duplication for `GraphBuilder` and `StateGraphBuilder` is inelegant, but can be improved if this idea is deemed appealing! Having access to a graph builder that provides "at construction time checking" sweetens the deal if one would want to move the runtime checks that exists in `Graph` into the `compile` function entirely. As suggested in this issue https://github.com/langchain-ai/langgraphjs/issues/88. If construction time checking is a type-level concern and compile time checking a runtime one; then it's possible to support both use cases. Making it possible to support construction methods that only have to be valid at compile time - then order of node and edge inserts does not matter. It only matters that the state is correct when calling compile. And for those wanting construction time validation (and "intellisense"), then the builder is available. Thanks @davidfant for reviewing and helping to find a bug prior to opening this. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-15 18:17:11 -05:00
yindo closed this issue 2026-02-15 18:17:11 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#499