langchainjs
langchainjs copied to clipboard
bind() method on RunnableLambda doesn't accept input parameters as documented
Checked other resources
- [x] I added a very descriptive title to this issue.
- [x] I searched the LangChain.js documentation with the integrated search.
- [x] I used the GitHub search to find a similar question and didn't find it.
- [x] I am sure that this is a bug in LangChain.js rather than my code.
- [x] The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
Example Code
When attempting to bind an input parameter to a RunnableLambda:
const exampleRunnable = RunnableLambda.from<{a: number, b: number}, number>(({a, b}) => {
return a + b
}).withConfig({
runName: "example-runnable",
})
exampleRunnable.bind({b: 2}).invoke({a: 1})
Error Message and Stack Trace (if applicable)
TypeScript throws the following errors:
Object literal may only specify known properties, and 'b' does not exist in type 'Partial<RunnableConfig<Record<string, any>>>'Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: number; b: number; }'
Description
The bind() method on RunnableLambda is not working as documented in the official LangChain.js documentation (https://js.langchain.com/docs/how_to/binding/). When trying to bind input parameters to a runnable, TypeScript reports that the parameters are not valid properties of RunnableConfig.
System Info
The issue you're encountering with the bind() method on RunnableLambda seems to stem from a misunderstanding of how the method is intended to be used. The bind() method is designed to bind configuration options, not input parameters directly. The kwargs parameter in the bind() method is expected to be of type Partial<CallOptions>, which is used for configuration purposes, not for binding input parameters like b in your example [1].
In your code, you're trying to bind an input parameter b directly, which is not supported by the bind() method as it currently stands. Instead, you should pass all required input parameters when invoking the runnable. The bind() method is meant for setting options like stop sequences or other configuration settings that modify the behavior of the runnable, not for binding input parameters that are part of the function's signature [1].
To resolve this, you should ensure that all input parameters required by the function are provided in the invoke() call, like so:
exampleRunnable.invoke({ a: 1, b: 2 });
This way, you provide all necessary inputs directly to the invoke() method, which aligns with the expected usage of RunnableLambda.
To continue talking to Dosu, mention @dosu.
Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Bug Report | Other
Okay, I've figured out the example:
const exampleRunnable = RunnableLambda.from<
{ a: number },
number,
RunnableConfig<{ b: number }>
>(({ a }, config) => {
return a + config.configurable.b;
}).withConfig({
runName: "example-runnable",
});
exampleRunnable.bind({ configurable: { b: 2 } }).invoke({ a: 1 });
I still feel like the Docs make it sound like this is the intended use case for bind:
"Sometimes we want to invoke a Runnable within a RunnableSequence with constant arguments that are not part of the output of the preceding Runnable in the sequence, and which are not part of the user input. We can use the Runnable.bind() method to set these arguments ahead of time."
Also, using the .bind() the way my example was using it is a much cleaner syntax that also aligns more with lambdas and how they are used in functional programming.
Thanks for reporting - the types on bind are a bit off across the board. Will fix!
Hi @hmbrg - thanks once again for bringing this to my attention!
Unfortunately the issues surrounding this go quite a bit deeper than I originally realized. Rather than completely rewriting this issue to capture everything I decided to just create a new issue (#8179) to track this. Please subscribe to that issue if you'd like updates on progress.