@langchain/core
Version:
Core LangChain.js abstractions and schemas
208 lines (207 loc) • 8.07 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunnableBranch = void 0;
const base_js_1 = require("./base.cjs");
const config_js_1 = require("./config.cjs");
const stream_js_1 = require("../utils/stream.cjs");
/**
* Class that represents a runnable branch. The RunnableBranch is
* initialized with an array of branches and a default branch. When invoked,
* it evaluates the condition of each branch in order and executes the
* corresponding branch if the condition is true. If none of the conditions
* are true, it executes the default branch.
* @example
* ```typescript
* const branch = RunnableBranch.from([
* [
* (x: { topic: string; question: string }) =>
* x.topic.toLowerCase().includes("anthropic"),
* anthropicChain,
* ],
* [
* (x: { topic: string; question: string }) =>
* x.topic.toLowerCase().includes("langchain"),
* langChainChain,
* ],
* generalChain,
* ]);
*
* const fullChain = RunnableSequence.from([
* {
* topic: classificationChain,
* question: (input: { question: string }) => input.question,
* },
* branch,
* ]);
*
* const result = await fullChain.invoke({
* question: "how do I use LangChain?",
* });
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
class RunnableBranch extends base_js_1.Runnable {
static lc_name() {
return "RunnableBranch";
}
constructor(fields) {
super(fields);
Object.defineProperty(this, "lc_namespace", {
enumerable: true,
configurable: true,
writable: true,
value: ["langchain_core", "runnables"]
});
Object.defineProperty(this, "lc_serializable", {
enumerable: true,
configurable: true,
writable: true,
value: true
});
Object.defineProperty(this, "default", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "branches", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.branches = fields.branches;
this.default = fields.default;
}
/**
* Convenience method for instantiating a RunnableBranch from
* RunnableLikes (objects, functions, or Runnables).
*
* Each item in the input except for the last one should be a
* tuple with two items. The first is a "condition" RunnableLike that
* returns "true" if the second RunnableLike in the tuple should run.
*
* The final item in the input should be a RunnableLike that acts as a
* default branch if no other branches match.
*
* @example
* ```ts
* import { RunnableBranch } from "@langchain/core/runnables";
*
* const branch = RunnableBranch.from([
* [(x: number) => x > 0, (x: number) => x + 1],
* [(x: number) => x < 0, (x: number) => x - 1],
* (x: number) => x
* ]);
* ```
* @param branches An array where the every item except the last is a tuple of [condition, runnable]
* pairs. The last item is a default runnable which is invoked if no other condition matches.
* @returns A new RunnableBranch.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static from(branches) {
if (branches.length < 1) {
throw new Error("RunnableBranch requires at least one branch");
}
const branchLikes = branches.slice(0, -1);
const coercedBranches = branchLikes.map(([condition, runnable]) => [
(0, base_js_1._coerceToRunnable)(condition),
(0, base_js_1._coerceToRunnable)(runnable),
]);
const defaultBranch = (0, base_js_1._coerceToRunnable)(branches[branches.length - 1]);
return new this({
branches: coercedBranches,
default: defaultBranch,
});
}
async _invoke(input, config, runManager) {
let result;
for (let i = 0; i < this.branches.length; i += 1) {
const [condition, branchRunnable] = this.branches[i];
const conditionValue = await condition.invoke(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild(`condition:${i + 1}`),
}));
if (conditionValue) {
result = await branchRunnable.invoke(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild(`branch:${i + 1}`),
}));
break;
}
}
if (!result) {
result = await this.default.invoke(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild("branch:default"),
}));
}
return result;
}
async invoke(input, config = {}) {
return this._callWithConfig(this._invoke, input, config);
}
async *_streamIterator(input, config) {
const callbackManager_ = await (0, config_js_1.getCallbackManagerForConfig)(config);
const runManager = await callbackManager_?.handleChainStart(this.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), config?.runId, undefined, undefined, undefined, config?.runName);
let finalOutput;
let finalOutputSupported = true;
let stream;
try {
for (let i = 0; i < this.branches.length; i += 1) {
const [condition, branchRunnable] = this.branches[i];
const conditionValue = await condition.invoke(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild(`condition:${i + 1}`),
}));
if (conditionValue) {
stream = await branchRunnable.stream(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild(`branch:${i + 1}`),
}));
for await (const chunk of stream) {
yield chunk;
if (finalOutputSupported) {
if (finalOutput === undefined) {
finalOutput = chunk;
}
else {
try {
finalOutput = (0, stream_js_1.concat)(finalOutput, chunk);
}
catch (e) {
finalOutput = undefined;
finalOutputSupported = false;
}
}
}
}
break;
}
}
if (stream === undefined) {
stream = await this.default.stream(input, (0, config_js_1.patchConfig)(config, {
callbacks: runManager?.getChild("branch:default"),
}));
for await (const chunk of stream) {
yield chunk;
if (finalOutputSupported) {
if (finalOutput === undefined) {
finalOutput = chunk;
}
else {
try {
finalOutput = (0, stream_js_1.concat)(finalOutput, chunk);
}
catch (e) {
finalOutput = undefined;
finalOutputSupported = false;
}
}
}
}
}
}
catch (e) {
await runManager?.handleChainError(e);
throw e;
}
await runManager?.handleChainEnd(finalOutput ?? {});
}
}
exports.RunnableBranch = RunnableBranch;
;