Skip to content

Commit

Permalink
core[patch]: Allow runnable func to have async (langchain-ai#4033)
Browse files Browse the repository at this point in the history
* core[patch]: Allow runnable func to have async

* chore: lint files

* cr

* undo cr

* pass config through

* tests

* chore: lint files
  • Loading branch information
bracesproul authored Jan 16, 2024
1 parent c189308 commit 6e970fb
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
8 changes: 5 additions & 3 deletions langchain-core/src/runnables/passthrough.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import type { RunnableConfig } from "./config.js";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type RunnablePassthroughFunc<RunInput = any> =
| ((input: RunInput) => void)
| ((input: RunInput, config?: RunnableConfig) => void);
| ((input: RunInput, config?: RunnableConfig) => void)
| ((input: RunInput) => Promise<void>)
| ((input: RunInput, config?: RunnableConfig) => Promise<void>);

/**
* A runnable to passthrough inputs unchanged or with additional keys.
Expand Down Expand Up @@ -64,7 +66,7 @@ export class RunnablePassthrough<RunInput> extends Runnable<
options?: Partial<RunnableConfig>
): Promise<RunInput> {
if (this.func) {
this.func(input);
await this.func(input, options);
}

return this._callWithConfig(
Expand Down Expand Up @@ -103,7 +105,7 @@ export class RunnablePassthrough<RunInput> extends Runnable<
}

if (this.func && finalOutput !== undefined) {
this.func(finalOutput);
await this.func(finalOutput, options);
}
}

Expand Down
28 changes: 28 additions & 0 deletions langchain-core/src/runnables/tests/runnable_passthrough.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FakeChatModel } from "../../utils/testing/index.js";
import { RunnablePassthrough } from "../passthrough.js";
import { JsonOutputParser } from "../../output_parsers/json.js";
import { RunnableSequence } from "../base.js";
import { RunnableConfig } from "../config.js";

test("RunnablePassthrough can call .assign and pass prev result through", async () => {
const promptTemplate = PromptTemplate.fromTemplate("{input}");
Expand Down Expand Up @@ -81,3 +82,30 @@ test("RunnablePassthrough can transform a function as constructor args", async (
expect(results).toEqual([1]);
expect(wasCalled).toEqual(true);
});

test("RunnablePassthrough can invoke a function and pass through config", async () => {
let wasCalled = false;
let addOneResult: number = 0;
const addOne = (input: number, config?: RunnableConfig) => {
wasCalled = true;
if (
!config?.configurable?.number ??
Number.isNaN(config?.configurable?.number)
) {
throw new Error("configurable.number is NaN");
}
console.log(config.configurable.number);
addOneResult = input + config.configurable.number;
};
const passthrough = new RunnablePassthrough<number>({
func: addOne,
});
const result = await passthrough.invoke(1, {
configurable: {
number: 1,
},
});
expect(result).toEqual(1);
expect(addOneResult).toEqual(2);
expect(wasCalled).toEqual(true);
});

0 comments on commit 6e970fb

Please sign in to comment.