-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to add Nodes and Edges dynamically before runtime #763
Comments
After further investigation, I think I have found the root cause of this issue. It stems from how type casting is implemented in the return this as StateGraph<SD, S, U, N | K, I, O, C>; This superficial type casting works for method chaining because each call receives a new cast, but fails for separate calls because the instance retains its original type. Interestingly, this is why addEdge works without chaining (it returns this without type casting) while addNode doesn't. This suggests the issue requires a deeper solution and it is not possible to solve with an easy fix. Any thoughts? Maybe it should be a new feature "adding nodes dynamically to a graph" |
@jacoblee93 @bracesproul Having worked with LangGraph since its early days, we're now trying to make our well-functioning graphs more generic and reusable. The current method chaining requirement is becoming a real bottleneck for this. We'd love to build our graphs from configuration, allowing us to:
Would you consider supporting an alternative to method chaining that would enable these patterns? This would make LangGraph even more powerful as a framework for building flexible, production-ready AI applications. Happy to share our experiences and specific use cases if helpful. |
Yeah would love to see what you're trying to do at a low level and how this blocks you - I think best we could do is have a |
Thanks for the response! To clarify: this isn't just about typing. In Python LangGraph, we can use stateGraph.addNode without issues. What we're trying to achieve is building configurable graphs from configuration: // We want to build the graph based on client configuration
const graph = new StateGraph(StateAnnotation);
clientConfig.enabledNodes.forEach(nodeName => {
graph.addNode(nodeName, availableNodes[nodeName]);
// Configure edges based on which nodes are enabled
}); The current method chaining requirement forces us to either:
Using @ts-ignore or disableTyping wouldn't solve this - it's not just about bypassing TypeScript errors, but about enabling proper graph construction from configuration before runtime. We're curious about LangGraph's vision regarding configurable graphs. The Python implementation allows this flexibility - is this an intentional design choice? Having this ability in TypeScript would align well with LangGraph's goal of building flexible, production-ready AI applications. Would love to hear your thoughts on this. |
I am pretty sure that in the early days of LangGraph this was possible. The first tutorials worked with For a more practical application. We have a chatbot with prebuilt tools (as agents) and these are configurable. But we would like to make this even more configurable by toggling these tools in a portal. We are using a supervisor that we build dynamically adding these available subagents based on the config. But right now we have to load all agents as node and create all edges from these node to END with some dynamic conditional edges in between. Hope this gives more insight in the practical solution. I am pretty sure LangGraph Cloud/Studio will benefit of this as well. |
I see - interesting. It sounds like something like |
Not exactly - disabling validation would still require us to work around the method chaining pattern. The core issue is that we want to build graphs programmatically from configuration, similar to how it works in Python LangGraph. Method chaining forces a static, linear definition of the graph. What we're looking for is the ability to construct graphs more dynamically, where nodes and edges can be added based on configuration - without having to build separate graph definitions for each possible combination. Is supporting this kind of configuration-based graph construction something that aligns with LangGraph's vision? Or is there perhaps a different pattern you'd recommend for achieving this? |
I think this sounds reasonable - but what error do you actually see with this? What about: // We want to build the graph based on client configuration
let graph = new StateGraph(StateAnnotation);
clientConfig.enabledNodes.forEach(nodeName => {
graph = graph.addNode(nodeName, availableNodes[nodeName]);
// Configure edges based on which nodes are enabled
}); |
Thanks for taking the time to have a look! Interesting solution you provide. I tried the reassignment approach, but it still forces us into a fixed, predefined graph structure. Here's what I tried: let stateGraph = new StateGraph(StateAnnotation);
stateGraph = stateGraph.addNode("nodeName", nodeFunction); This results in: Type 'StateGraph<...>' is not assignable to type 'StateGraph<...>'.
Types of property 'waitingEdges' are incompatible.
Type 'Set<[("__start__" | "nodeName")[], "__start__" | "nodeName"]>' is not assignable to type 'Set<["__start__"[], "__start__"]>'. This doesn't work - not just because of TypeScript, but because the underlying StateGraph seems designed around static, chain-based construction rather than dynamic configuration. Making it impossible to assign nodes dynamically. As a workaround we now add all nodes hardcoded and create for all nodes a static routing to END. And in the middel we use a dynamic edge which only routes the available nodes inside the graph. For now it's okay, but when we have 100+ nodes we can choose of, it get's a bit messy and dirty :) As an answer to your first question. // When using:
const stateGraph = new StateGraph(StateAnnotation);
stateGraph.addNode("nodeName", nodeFunction);
stateGraph.addEdge("nodeName", END); This fails with: Argument of type '"nodeName"' is not assignable to parameter of type '"__start__"'.ts(2345) Meaning the StateGraph structure doesn't support adding nodes independently from the chain. |
Description:
When adding nodes to a StateGraph, the type inference only works correctly when using method chaining syntax. Adding nodes dynamically using separate
stateGraph.addNode()
calls breaks the type accumulation in theN
type parameter.Example of working code (with correct type inference):
Example of code that breaks type inference:
This makes it difficult to dynamically add nodes to the graph, as we're forced to use method chaining. This seems unintuitive and limits the flexibility of the StateGraph implementation.
Expected behavior:
Both approaches should maintain correct type inference, allowing for more flexible ways to add nodes to the graph, especially when dealing with dynamic configurations.
Would it be possible to adjust the type definitions to maintain type accumulation in the N type parameter regardless of whether method chaining is used?
The text was updated successfully, but these errors were encountered: