base.js 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394
  1. import { z } from "zod";
  2. import pRetry from "p-retry";
  3. import { v4 as uuidv4 } from "uuid";
  4. import { isTraceableFunction, } from "langsmith/singletons/traceable";
  5. import { LogStreamCallbackHandler, RunLog, RunLogPatch, isLogStreamHandler, } from "../tracers/log_stream.js";
  6. import { EventStreamCallbackHandler, isStreamEventsHandler, } from "../tracers/event_stream.js";
  7. import { Serializable } from "../load/serializable.js";
  8. import { IterableReadableStream, concat, atee, pipeGeneratorWithSetup, AsyncGeneratorWithSetup, } from "../utils/stream.js";
  9. import { raceWithSignal } from "../utils/signal.js";
  10. import { DEFAULT_RECURSION_LIMIT, ensureConfig, getCallbackManagerForConfig, mergeConfigs, patchConfig, pickRunnableConfigKeys, } from "./config.js";
  11. import { AsyncCaller } from "../utils/async_caller.js";
  12. import { RootListenersTracer } from "../tracers/root_listener.js";
  13. import { _RootEventFilter, isRunnableInterface } from "./utils.js";
  14. import { AsyncLocalStorageProviderSingleton } from "../singletons/index.js";
  15. import { Graph } from "./graph.js";
  16. import { convertToHttpEventStream } from "./wrappers.js";
  17. import { consumeAsyncIterableInContext, consumeIteratorInContext, isAsyncIterable, isIterableIterator, isIterator, } from "./iter.js";
  18. import { _isToolCall, ToolInputParsingException } from "../tools/utils.js";
  19. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  20. export function _coerceToDict(value, defaultKey) {
  21. return value &&
  22. !Array.isArray(value) &&
  23. // eslint-disable-next-line no-instanceof/no-instanceof
  24. !(value instanceof Date) &&
  25. typeof value === "object"
  26. ? value
  27. : { [defaultKey]: value };
  28. }
  29. /**
  30. * A Runnable is a generic unit of work that can be invoked, batched, streamed, and/or
  31. * transformed.
  32. */
  33. export class Runnable extends Serializable {
  34. constructor() {
  35. super(...arguments);
  36. Object.defineProperty(this, "lc_runnable", {
  37. enumerable: true,
  38. configurable: true,
  39. writable: true,
  40. value: true
  41. });
  42. Object.defineProperty(this, "name", {
  43. enumerable: true,
  44. configurable: true,
  45. writable: true,
  46. value: void 0
  47. });
  48. }
  49. getName(suffix) {
  50. const name =
  51. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  52. this.name ?? this.constructor.lc_name() ?? this.constructor.name;
  53. return suffix ? `${name}${suffix}` : name;
  54. }
  55. /**
  56. * Bind arguments to a Runnable, returning a new Runnable.
  57. * @param kwargs
  58. * @returns A new RunnableBinding that, when invoked, will apply the bound args.
  59. *
  60. * @deprecated Use {@link withConfig} instead. This will be removed in the next breaking release.
  61. */
  62. bind(kwargs) {
  63. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  64. return new RunnableBinding({ bound: this, kwargs, config: {} });
  65. }
  66. /**
  67. * Return a new Runnable that maps a list of inputs to a list of outputs,
  68. * by calling invoke() with each input.
  69. *
  70. * @deprecated This will be removed in the next breaking release.
  71. */
  72. map() {
  73. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  74. return new RunnableEach({ bound: this });
  75. }
  76. /**
  77. * Add retry logic to an existing runnable.
  78. * @param fields.stopAfterAttempt The number of attempts to retry.
  79. * @param fields.onFailedAttempt A function that is called when a retry fails.
  80. * @returns A new RunnableRetry that, when invoked, will retry according to the parameters.
  81. */
  82. withRetry(fields) {
  83. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  84. return new RunnableRetry({
  85. bound: this,
  86. kwargs: {},
  87. config: {},
  88. maxAttemptNumber: fields?.stopAfterAttempt,
  89. ...fields,
  90. });
  91. }
  92. /**
  93. * Bind config to a Runnable, returning a new Runnable.
  94. * @param config New configuration parameters to attach to the new runnable.
  95. * @returns A new RunnableBinding with a config matching what's passed.
  96. */
  97. withConfig(config) {
  98. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  99. return new RunnableBinding({
  100. bound: this,
  101. config,
  102. kwargs: {},
  103. });
  104. }
  105. /**
  106. * Create a new runnable from the current one that will try invoking
  107. * other passed fallback runnables if the initial invocation fails.
  108. * @param fields.fallbacks Other runnables to call if the runnable errors.
  109. * @returns A new RunnableWithFallbacks.
  110. */
  111. withFallbacks(fields) {
  112. const fallbacks = Array.isArray(fields) ? fields : fields.fallbacks;
  113. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  114. return new RunnableWithFallbacks({
  115. runnable: this,
  116. fallbacks,
  117. });
  118. }
  119. _getOptionsList(options, length = 0) {
  120. if (Array.isArray(options) && options.length !== length) {
  121. throw new Error(`Passed "options" must be an array with the same length as the inputs, but got ${options.length} options for ${length} inputs`);
  122. }
  123. if (Array.isArray(options)) {
  124. return options.map(ensureConfig);
  125. }
  126. if (length > 1 && !Array.isArray(options) && options.runId) {
  127. console.warn("Provided runId will be used only for the first element of the batch.");
  128. const subsequent = Object.fromEntries(Object.entries(options).filter(([key]) => key !== "runId"));
  129. return Array.from({ length }, (_, i) => ensureConfig(i === 0 ? options : subsequent));
  130. }
  131. return Array.from({ length }, () => ensureConfig(options));
  132. }
  133. async batch(inputs, options, batchOptions) {
  134. const configList = this._getOptionsList(options ?? {}, inputs.length);
  135. const maxConcurrency = configList[0]?.maxConcurrency ?? batchOptions?.maxConcurrency;
  136. const caller = new AsyncCaller({
  137. maxConcurrency,
  138. onFailedAttempt: (e) => {
  139. throw e;
  140. },
  141. });
  142. const batchCalls = inputs.map((input, i) => caller.call(async () => {
  143. try {
  144. const result = await this.invoke(input, configList[i]);
  145. return result;
  146. }
  147. catch (e) {
  148. if (batchOptions?.returnExceptions) {
  149. return e;
  150. }
  151. throw e;
  152. }
  153. }));
  154. return Promise.all(batchCalls);
  155. }
  156. /**
  157. * Default streaming implementation.
  158. * Subclasses should override this method if they support streaming output.
  159. * @param input
  160. * @param options
  161. */
  162. async *_streamIterator(input, options) {
  163. yield this.invoke(input, options);
  164. }
  165. /**
  166. * Stream output in chunks.
  167. * @param input
  168. * @param options
  169. * @returns A readable stream that is also an iterable.
  170. */
  171. async stream(input, options) {
  172. // Buffer the first streamed chunk to allow for initial errors
  173. // to surface immediately.
  174. const config = ensureConfig(options);
  175. const wrappedGenerator = new AsyncGeneratorWithSetup({
  176. generator: this._streamIterator(input, config),
  177. config,
  178. });
  179. await wrappedGenerator.setup;
  180. return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
  181. }
  182. _separateRunnableConfigFromCallOptions(options) {
  183. let runnableConfig;
  184. if (options === undefined) {
  185. runnableConfig = ensureConfig(options);
  186. }
  187. else {
  188. runnableConfig = ensureConfig({
  189. callbacks: options.callbacks,
  190. tags: options.tags,
  191. metadata: options.metadata,
  192. runName: options.runName,
  193. configurable: options.configurable,
  194. recursionLimit: options.recursionLimit,
  195. maxConcurrency: options.maxConcurrency,
  196. runId: options.runId,
  197. timeout: options.timeout,
  198. signal: options.signal,
  199. });
  200. }
  201. const callOptions = { ...options };
  202. delete callOptions.callbacks;
  203. delete callOptions.tags;
  204. delete callOptions.metadata;
  205. delete callOptions.runName;
  206. delete callOptions.configurable;
  207. delete callOptions.recursionLimit;
  208. delete callOptions.maxConcurrency;
  209. delete callOptions.runId;
  210. delete callOptions.timeout;
  211. delete callOptions.signal;
  212. return [runnableConfig, callOptions];
  213. }
  214. async _callWithConfig(func, input, options) {
  215. const config = ensureConfig(options);
  216. const callbackManager_ = await getCallbackManagerForConfig(config);
  217. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), config.runId, config?.runType, undefined, undefined, config?.runName ?? this.getName());
  218. delete config.runId;
  219. let output;
  220. try {
  221. const promise = func.call(this, input, config, runManager);
  222. output = await raceWithSignal(promise, options?.signal);
  223. }
  224. catch (e) {
  225. await runManager?.handleChainError(e);
  226. throw e;
  227. }
  228. await runManager?.handleChainEnd(_coerceToDict(output, "output"));
  229. return output;
  230. }
  231. /**
  232. * Internal method that handles batching and configuration for a runnable
  233. * It takes a function, input values, and optional configuration, and
  234. * returns a promise that resolves to the output values.
  235. * @param func The function to be executed for each input value.
  236. * @param input The input values to be processed.
  237. * @param config Optional configuration for the function execution.
  238. * @returns A promise that resolves to the output values.
  239. */
  240. async _batchWithConfig(func, inputs, options, batchOptions) {
  241. const optionsList = this._getOptionsList(options ?? {}, inputs.length);
  242. const callbackManagers = await Promise.all(optionsList.map(getCallbackManagerForConfig));
  243. const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => {
  244. const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), _coerceToDict(inputs[i], "input"), optionsList[i].runId, optionsList[i].runType, undefined, undefined, optionsList[i].runName ?? this.getName());
  245. delete optionsList[i].runId;
  246. return handleStartRes;
  247. }));
  248. let outputs;
  249. try {
  250. const promise = func.call(this, inputs, optionsList, runManagers, batchOptions);
  251. outputs = await raceWithSignal(promise, optionsList?.[0]?.signal);
  252. }
  253. catch (e) {
  254. await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e)));
  255. throw e;
  256. }
  257. await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(_coerceToDict(outputs, "output"))));
  258. return outputs;
  259. }
  260. /**
  261. * Helper method to transform an Iterator of Input values into an Iterator of
  262. * Output values, with callbacks.
  263. * Use this to implement `stream()` or `transform()` in Runnable subclasses.
  264. */
  265. async *_transformStreamWithConfig(inputGenerator, transformer, options) {
  266. let finalInput;
  267. let finalInputSupported = true;
  268. let finalOutput;
  269. let finalOutputSupported = true;
  270. const config = ensureConfig(options);
  271. const callbackManager_ = await getCallbackManagerForConfig(config);
  272. async function* wrapInputForTracing() {
  273. for await (const chunk of inputGenerator) {
  274. if (finalInputSupported) {
  275. if (finalInput === undefined) {
  276. finalInput = chunk;
  277. }
  278. else {
  279. try {
  280. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  281. finalInput = concat(finalInput, chunk);
  282. }
  283. catch {
  284. finalInput = undefined;
  285. finalInputSupported = false;
  286. }
  287. }
  288. }
  289. yield chunk;
  290. }
  291. }
  292. let runManager;
  293. try {
  294. const pipe = await pipeGeneratorWithSetup(transformer.bind(this), wrapInputForTracing(), async () => callbackManager_?.handleChainStart(this.toJSON(), { input: "" }, config.runId, config.runType, undefined, undefined, config.runName ?? this.getName()), options?.signal, config);
  295. delete config.runId;
  296. runManager = pipe.setup;
  297. const streamEventsHandler = runManager?.handlers.find(isStreamEventsHandler);
  298. let iterator = pipe.output;
  299. if (streamEventsHandler !== undefined && runManager !== undefined) {
  300. iterator = streamEventsHandler.tapOutputIterable(runManager.runId, iterator);
  301. }
  302. const streamLogHandler = runManager?.handlers.find(isLogStreamHandler);
  303. if (streamLogHandler !== undefined && runManager !== undefined) {
  304. iterator = streamLogHandler.tapOutputIterable(runManager.runId, iterator);
  305. }
  306. for await (const chunk of iterator) {
  307. yield chunk;
  308. if (finalOutputSupported) {
  309. if (finalOutput === undefined) {
  310. finalOutput = chunk;
  311. }
  312. else {
  313. try {
  314. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  315. finalOutput = concat(finalOutput, chunk);
  316. }
  317. catch {
  318. finalOutput = undefined;
  319. finalOutputSupported = false;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. catch (e) {
  326. await runManager?.handleChainError(e, undefined, undefined, undefined, {
  327. inputs: _coerceToDict(finalInput, "input"),
  328. });
  329. throw e;
  330. }
  331. await runManager?.handleChainEnd(finalOutput ?? {}, undefined, undefined, undefined, { inputs: _coerceToDict(finalInput, "input") });
  332. }
  333. getGraph(_) {
  334. const graph = new Graph();
  335. // TODO: Add input schema for runnables
  336. const inputNode = graph.addNode({
  337. name: `${this.getName()}Input`,
  338. schema: z.any(),
  339. });
  340. const runnableNode = graph.addNode(this);
  341. // TODO: Add output schemas for runnables
  342. const outputNode = graph.addNode({
  343. name: `${this.getName()}Output`,
  344. schema: z.any(),
  345. });
  346. graph.addEdge(inputNode, runnableNode);
  347. graph.addEdge(runnableNode, outputNode);
  348. return graph;
  349. }
  350. /**
  351. * Create a new runnable sequence that runs each individual runnable in series,
  352. * piping the output of one runnable into another runnable or runnable-like.
  353. * @param coerceable A runnable, function, or object whose values are functions or runnables.
  354. * @returns A new runnable sequence.
  355. */
  356. pipe(coerceable) {
  357. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  358. return new RunnableSequence({
  359. first: this,
  360. last: _coerceToRunnable(coerceable),
  361. });
  362. }
  363. /**
  364. * Pick keys from the dict output of this runnable. Returns a new runnable.
  365. */
  366. pick(keys) {
  367. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  368. return this.pipe(new RunnablePick(keys));
  369. }
  370. /**
  371. * Assigns new fields to the dict output of this runnable. Returns a new runnable.
  372. */
  373. assign(mapping) {
  374. return this.pipe(
  375. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  376. new RunnableAssign(
  377. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  378. new RunnableMap({ steps: mapping })));
  379. }
  380. /**
  381. * Default implementation of transform, which buffers input and then calls stream.
  382. * Subclasses should override this method if they can start producing output while
  383. * input is still being generated.
  384. * @param generator
  385. * @param options
  386. */
  387. async *transform(generator, options) {
  388. let finalChunk;
  389. for await (const chunk of generator) {
  390. if (finalChunk === undefined) {
  391. finalChunk = chunk;
  392. }
  393. else {
  394. // Make a best effort to gather, for any type that supports concat.
  395. // This method should throw an error if gathering fails.
  396. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  397. finalChunk = concat(finalChunk, chunk);
  398. }
  399. }
  400. yield* this._streamIterator(finalChunk, ensureConfig(options));
  401. }
  402. /**
  403. * Stream all output from a runnable, as reported to the callback system.
  404. * This includes all inner runs of LLMs, Retrievers, Tools, etc.
  405. * Output is streamed as Log objects, which include a list of
  406. * jsonpatch ops that describe how the state of the run has changed in each
  407. * step, and the final state of the run.
  408. * The jsonpatch ops can be applied in order to construct state.
  409. * @param input
  410. * @param options
  411. * @param streamOptions
  412. */
  413. async *streamLog(input, options, streamOptions) {
  414. const logStreamCallbackHandler = new LogStreamCallbackHandler({
  415. ...streamOptions,
  416. autoClose: false,
  417. _schemaFormat: "original",
  418. });
  419. const config = ensureConfig(options);
  420. yield* this._streamLog(input, logStreamCallbackHandler, config);
  421. }
  422. async *_streamLog(input, logStreamCallbackHandler, config) {
  423. const { callbacks } = config;
  424. if (callbacks === undefined) {
  425. // eslint-disable-next-line no-param-reassign
  426. config.callbacks = [logStreamCallbackHandler];
  427. }
  428. else if (Array.isArray(callbacks)) {
  429. // eslint-disable-next-line no-param-reassign
  430. config.callbacks = callbacks.concat([logStreamCallbackHandler]);
  431. }
  432. else {
  433. const copiedCallbacks = callbacks.copy();
  434. copiedCallbacks.addHandler(logStreamCallbackHandler, true);
  435. // eslint-disable-next-line no-param-reassign
  436. config.callbacks = copiedCallbacks;
  437. }
  438. const runnableStreamPromise = this.stream(input, config);
  439. async function consumeRunnableStream() {
  440. try {
  441. const runnableStream = await runnableStreamPromise;
  442. for await (const chunk of runnableStream) {
  443. const patch = new RunLogPatch({
  444. ops: [
  445. {
  446. op: "add",
  447. path: "/streamed_output/-",
  448. value: chunk,
  449. },
  450. ],
  451. });
  452. await logStreamCallbackHandler.writer.write(patch);
  453. }
  454. }
  455. finally {
  456. await logStreamCallbackHandler.writer.close();
  457. }
  458. }
  459. const runnableStreamConsumePromise = consumeRunnableStream();
  460. try {
  461. for await (const log of logStreamCallbackHandler) {
  462. yield log;
  463. }
  464. }
  465. finally {
  466. await runnableStreamConsumePromise;
  467. }
  468. }
  469. streamEvents(input, options, streamOptions) {
  470. let stream;
  471. if (options.version === "v1") {
  472. stream = this._streamEventsV1(input, options, streamOptions);
  473. }
  474. else if (options.version === "v2") {
  475. stream = this._streamEventsV2(input, options, streamOptions);
  476. }
  477. else {
  478. throw new Error(`Only versions "v1" and "v2" of the schema are currently supported.`);
  479. }
  480. if (options.encoding === "text/event-stream") {
  481. return convertToHttpEventStream(stream);
  482. }
  483. else {
  484. return IterableReadableStream.fromAsyncGenerator(stream);
  485. }
  486. }
  487. async *_streamEventsV2(input, options, streamOptions) {
  488. const eventStreamer = new EventStreamCallbackHandler({
  489. ...streamOptions,
  490. autoClose: false,
  491. });
  492. const config = ensureConfig(options);
  493. const runId = config.runId ?? uuidv4();
  494. config.runId = runId;
  495. const callbacks = config.callbacks;
  496. if (callbacks === undefined) {
  497. config.callbacks = [eventStreamer];
  498. }
  499. else if (Array.isArray(callbacks)) {
  500. config.callbacks = callbacks.concat(eventStreamer);
  501. }
  502. else {
  503. const copiedCallbacks = callbacks.copy();
  504. copiedCallbacks.addHandler(eventStreamer, true);
  505. // eslint-disable-next-line no-param-reassign
  506. config.callbacks = copiedCallbacks;
  507. }
  508. const abortController = new AbortController();
  509. // Call the runnable in streaming mode,
  510. // add each chunk to the output stream
  511. const outerThis = this;
  512. async function consumeRunnableStream() {
  513. try {
  514. let signal;
  515. if (options?.signal) {
  516. if ("any" in AbortSignal) {
  517. // Use native AbortSignal.any() if available (Node 19+)
  518. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  519. signal = AbortSignal.any([
  520. abortController.signal,
  521. options.signal,
  522. ]);
  523. }
  524. else {
  525. // Fallback for Node 18 and below - just use the provided signal
  526. signal = options.signal;
  527. // Ensure we still abort our controller when the parent signal aborts
  528. options.signal.addEventListener("abort", () => {
  529. abortController.abort();
  530. }, { once: true });
  531. }
  532. }
  533. else {
  534. signal = abortController.signal;
  535. }
  536. const runnableStream = await outerThis.stream(input, {
  537. ...config,
  538. signal,
  539. });
  540. const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream);
  541. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  542. for await (const _ of tappedStream) {
  543. // Just iterate so that the callback handler picks up events
  544. if (abortController.signal.aborted)
  545. break;
  546. }
  547. }
  548. finally {
  549. await eventStreamer.finish();
  550. }
  551. }
  552. const runnableStreamConsumePromise = consumeRunnableStream();
  553. let firstEventSent = false;
  554. let firstEventRunId;
  555. try {
  556. for await (const event of eventStreamer) {
  557. // This is a work-around an issue where the inputs into the
  558. // chain are not available until the entire input is consumed.
  559. // As a temporary solution, we'll modify the input to be the input
  560. // that was passed into the chain.
  561. if (!firstEventSent) {
  562. event.data.input = input;
  563. firstEventSent = true;
  564. firstEventRunId = event.run_id;
  565. yield event;
  566. continue;
  567. }
  568. if (event.run_id === firstEventRunId && event.event.endsWith("_end")) {
  569. // If it's the end event corresponding to the root runnable
  570. // we dont include the input in the event since it's guaranteed
  571. // to be included in the first event.
  572. if (event.data?.input) {
  573. delete event.data.input;
  574. }
  575. }
  576. yield event;
  577. }
  578. }
  579. finally {
  580. abortController.abort();
  581. await runnableStreamConsumePromise;
  582. }
  583. }
  584. async *_streamEventsV1(input, options, streamOptions) {
  585. let runLog;
  586. let hasEncounteredStartEvent = false;
  587. const config = ensureConfig(options);
  588. const rootTags = config.tags ?? [];
  589. const rootMetadata = config.metadata ?? {};
  590. const rootName = config.runName ?? this.getName();
  591. const logStreamCallbackHandler = new LogStreamCallbackHandler({
  592. ...streamOptions,
  593. autoClose: false,
  594. _schemaFormat: "streaming_events",
  595. });
  596. const rootEventFilter = new _RootEventFilter({
  597. ...streamOptions,
  598. });
  599. const logStream = this._streamLog(input, logStreamCallbackHandler, config);
  600. for await (const log of logStream) {
  601. if (!runLog) {
  602. runLog = RunLog.fromRunLogPatch(log);
  603. }
  604. else {
  605. runLog = runLog.concat(log);
  606. }
  607. if (runLog.state === undefined) {
  608. throw new Error(`Internal error: "streamEvents" state is missing. Please open a bug report.`);
  609. }
  610. // Yield the start event for the root runnable if it hasn't been seen.
  611. // The root run is never filtered out
  612. if (!hasEncounteredStartEvent) {
  613. hasEncounteredStartEvent = true;
  614. const state = { ...runLog.state };
  615. const event = {
  616. run_id: state.id,
  617. event: `on_${state.type}_start`,
  618. name: rootName,
  619. tags: rootTags,
  620. metadata: rootMetadata,
  621. data: {
  622. input,
  623. },
  624. };
  625. if (rootEventFilter.includeEvent(event, state.type)) {
  626. yield event;
  627. }
  628. }
  629. const paths = log.ops
  630. .filter((op) => op.path.startsWith("/logs/"))
  631. .map((op) => op.path.split("/")[2]);
  632. const dedupedPaths = [...new Set(paths)];
  633. for (const path of dedupedPaths) {
  634. let eventType;
  635. let data = {};
  636. const logEntry = runLog.state.logs[path];
  637. if (logEntry.end_time === undefined) {
  638. if (logEntry.streamed_output.length > 0) {
  639. eventType = "stream";
  640. }
  641. else {
  642. eventType = "start";
  643. }
  644. }
  645. else {
  646. eventType = "end";
  647. }
  648. if (eventType === "start") {
  649. // Include the inputs with the start event if they are available.
  650. // Usually they will NOT be available for components that operate
  651. // on streams, since those components stream the input and
  652. // don't know its final value until the end of the stream.
  653. if (logEntry.inputs !== undefined) {
  654. data.input = logEntry.inputs;
  655. }
  656. }
  657. else if (eventType === "end") {
  658. if (logEntry.inputs !== undefined) {
  659. data.input = logEntry.inputs;
  660. }
  661. data.output = logEntry.final_output;
  662. }
  663. else if (eventType === "stream") {
  664. const chunkCount = logEntry.streamed_output.length;
  665. if (chunkCount !== 1) {
  666. throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${logEntry.name}"`);
  667. }
  668. data = { chunk: logEntry.streamed_output[0] };
  669. // Clean up the stream, we don't need it anymore.
  670. // And this avoids duplicates as well!
  671. logEntry.streamed_output = [];
  672. }
  673. yield {
  674. event: `on_${logEntry.type}_${eventType}`,
  675. name: logEntry.name,
  676. run_id: logEntry.id,
  677. tags: logEntry.tags,
  678. metadata: logEntry.metadata,
  679. data,
  680. };
  681. }
  682. // Finally, we take care of the streaming output from the root chain
  683. // if there is any.
  684. const { state } = runLog;
  685. if (state.streamed_output.length > 0) {
  686. const chunkCount = state.streamed_output.length;
  687. if (chunkCount !== 1) {
  688. throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${state.name}"`);
  689. }
  690. const data = { chunk: state.streamed_output[0] };
  691. // Clean up the stream, we don't need it anymore.
  692. state.streamed_output = [];
  693. const event = {
  694. event: `on_${state.type}_stream`,
  695. run_id: state.id,
  696. tags: rootTags,
  697. metadata: rootMetadata,
  698. name: rootName,
  699. data,
  700. };
  701. if (rootEventFilter.includeEvent(event, state.type)) {
  702. yield event;
  703. }
  704. }
  705. }
  706. const state = runLog?.state;
  707. if (state !== undefined) {
  708. // Finally, yield the end event for the root runnable.
  709. const event = {
  710. event: `on_${state.type}_end`,
  711. name: rootName,
  712. run_id: state.id,
  713. tags: rootTags,
  714. metadata: rootMetadata,
  715. data: {
  716. output: state.final_output,
  717. },
  718. };
  719. if (rootEventFilter.includeEvent(event, state.type))
  720. yield event;
  721. }
  722. }
  723. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  724. static isRunnable(thing) {
  725. return isRunnableInterface(thing);
  726. }
  727. /**
  728. * Bind lifecycle listeners to a Runnable, returning a new Runnable.
  729. * The Run object contains information about the run, including its id,
  730. * type, input, output, error, startTime, endTime, and any tags or metadata
  731. * added to the run.
  732. *
  733. * @param {Object} params - The object containing the callback functions.
  734. * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object.
  735. * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object.
  736. * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object.
  737. */
  738. withListeners({ onStart, onEnd, onError, }) {
  739. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  740. return new RunnableBinding({
  741. bound: this,
  742. config: {},
  743. configFactories: [
  744. (config) => ({
  745. callbacks: [
  746. new RootListenersTracer({
  747. config,
  748. onStart,
  749. onEnd,
  750. onError,
  751. }),
  752. ],
  753. }),
  754. ],
  755. });
  756. }
  757. /**
  758. * Convert a runnable to a tool. Return a new instance of `RunnableToolLike`
  759. * which contains the runnable, name, description and schema.
  760. *
  761. * @template {T extends RunInput = RunInput} RunInput - The input type of the runnable. Should be the same as the `RunInput` type of the runnable.
  762. *
  763. * @param fields
  764. * @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable.
  765. * @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided.
  766. * @param {z.ZodType<T>} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable.
  767. * @returns {RunnableToolLike<z.ZodType<T>, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool.
  768. */
  769. asTool(fields) {
  770. return convertRunnableToTool(this, fields);
  771. }
  772. }
  773. /**
  774. * Wraps a runnable and applies partial config upon invocation.
  775. *
  776. * @example
  777. * ```typescript
  778. * import {
  779. * type RunnableConfig,
  780. * RunnableLambda,
  781. * } from "@langchain/core/runnables";
  782. *
  783. * const enhanceProfile = (
  784. * profile: Record<string, any>,
  785. * config?: RunnableConfig
  786. * ) => {
  787. * if (config?.configurable?.role) {
  788. * return { ...profile, role: config.configurable.role };
  789. * }
  790. * return profile;
  791. * };
  792. *
  793. * const runnable = RunnableLambda.from(enhanceProfile);
  794. *
  795. * // Bind configuration to the runnable to set the user's role dynamically
  796. * const adminRunnable = runnable.bind({ configurable: { role: "Admin" } });
  797. * const userRunnable = runnable.bind({ configurable: { role: "User" } });
  798. *
  799. * const result1 = await adminRunnable.invoke({
  800. * name: "Alice",
  801. * email: "alice@example.com"
  802. * });
  803. *
  804. * // { name: "Alice", email: "alice@example.com", role: "Admin" }
  805. *
  806. * const result2 = await userRunnable.invoke({
  807. * name: "Bob",
  808. * email: "bob@example.com"
  809. * });
  810. *
  811. * // { name: "Bob", email: "bob@example.com", role: "User" }
  812. * ```
  813. */
  814. export class RunnableBinding extends Runnable {
  815. static lc_name() {
  816. return "RunnableBinding";
  817. }
  818. constructor(fields) {
  819. super(fields);
  820. Object.defineProperty(this, "lc_namespace", {
  821. enumerable: true,
  822. configurable: true,
  823. writable: true,
  824. value: ["langchain_core", "runnables"]
  825. });
  826. Object.defineProperty(this, "lc_serializable", {
  827. enumerable: true,
  828. configurable: true,
  829. writable: true,
  830. value: true
  831. });
  832. Object.defineProperty(this, "bound", {
  833. enumerable: true,
  834. configurable: true,
  835. writable: true,
  836. value: void 0
  837. });
  838. Object.defineProperty(this, "config", {
  839. enumerable: true,
  840. configurable: true,
  841. writable: true,
  842. value: void 0
  843. });
  844. Object.defineProperty(this, "kwargs", {
  845. enumerable: true,
  846. configurable: true,
  847. writable: true,
  848. value: void 0
  849. });
  850. Object.defineProperty(this, "configFactories", {
  851. enumerable: true,
  852. configurable: true,
  853. writable: true,
  854. value: void 0
  855. });
  856. this.bound = fields.bound;
  857. this.kwargs = fields.kwargs;
  858. this.config = fields.config;
  859. this.configFactories = fields.configFactories;
  860. }
  861. getName(suffix) {
  862. return this.bound.getName(suffix);
  863. }
  864. async _mergeConfig(...options) {
  865. const config = mergeConfigs(this.config, ...options);
  866. return mergeConfigs(config, ...(this.configFactories
  867. ? await Promise.all(this.configFactories.map(async (configFactory) => await configFactory(config)))
  868. : []));
  869. }
  870. /**
  871. * Binds the runnable with the specified arguments.
  872. * @param kwargs The arguments to bind the runnable with.
  873. * @returns A new instance of the `RunnableBinding` class that is bound with the specified arguments.
  874. *
  875. * @deprecated Use {@link withConfig} instead. This will be removed in the next breaking release.
  876. */
  877. bind(kwargs) {
  878. return new this.constructor({
  879. bound: this.bound,
  880. kwargs: { ...this.kwargs, ...kwargs },
  881. config: this.config,
  882. });
  883. }
  884. withConfig(config) {
  885. return new this.constructor({
  886. bound: this.bound,
  887. kwargs: this.kwargs,
  888. config: { ...this.config, ...config },
  889. });
  890. }
  891. withRetry(fields) {
  892. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  893. return new RunnableRetry({
  894. bound: this.bound,
  895. kwargs: this.kwargs,
  896. config: this.config,
  897. maxAttemptNumber: fields?.stopAfterAttempt,
  898. ...fields,
  899. });
  900. }
  901. async invoke(input, options) {
  902. return this.bound.invoke(input, await this._mergeConfig(ensureConfig(options), this.kwargs));
  903. }
  904. async batch(inputs, options, batchOptions) {
  905. const mergedOptions = Array.isArray(options)
  906. ? await Promise.all(options.map(async (individualOption) => this._mergeConfig(ensureConfig(individualOption), this.kwargs)))
  907. : await this._mergeConfig(ensureConfig(options), this.kwargs);
  908. return this.bound.batch(inputs, mergedOptions, batchOptions);
  909. }
  910. async *_streamIterator(input, options) {
  911. yield* this.bound._streamIterator(input, await this._mergeConfig(ensureConfig(options), this.kwargs));
  912. }
  913. async stream(input, options) {
  914. return this.bound.stream(input, await this._mergeConfig(ensureConfig(options), this.kwargs));
  915. }
  916. async *transform(generator, options) {
  917. yield* this.bound.transform(generator, await this._mergeConfig(ensureConfig(options), this.kwargs));
  918. }
  919. streamEvents(input, options, streamOptions) {
  920. // eslint-disable-next-line @typescript-eslint/no-this-alias
  921. const outerThis = this;
  922. const generator = async function* () {
  923. yield* outerThis.bound.streamEvents(input, {
  924. ...(await outerThis._mergeConfig(ensureConfig(options), outerThis.kwargs)),
  925. version: options.version,
  926. }, streamOptions);
  927. };
  928. return IterableReadableStream.fromAsyncGenerator(generator());
  929. }
  930. static isRunnableBinding(
  931. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  932. thing
  933. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  934. ) {
  935. return thing.bound && Runnable.isRunnable(thing.bound);
  936. }
  937. /**
  938. * Bind lifecycle listeners to a Runnable, returning a new Runnable.
  939. * The Run object contains information about the run, including its id,
  940. * type, input, output, error, startTime, endTime, and any tags or metadata
  941. * added to the run.
  942. *
  943. * @param {Object} params - The object containing the callback functions.
  944. * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object.
  945. * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object.
  946. * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object.
  947. */
  948. withListeners({ onStart, onEnd, onError, }) {
  949. return new RunnableBinding({
  950. bound: this.bound,
  951. kwargs: this.kwargs,
  952. config: this.config,
  953. configFactories: [
  954. (config) => ({
  955. callbacks: [
  956. new RootListenersTracer({
  957. config,
  958. onStart,
  959. onEnd,
  960. onError,
  961. }),
  962. ],
  963. }),
  964. ],
  965. });
  966. }
  967. }
  968. /**
  969. * A runnable that delegates calls to another runnable
  970. * with each element of the input sequence.
  971. * @example
  972. * ```typescript
  973. * import { RunnableEach, RunnableLambda } from "@langchain/core/runnables";
  974. *
  975. * const toUpperCase = (input: string): string => input.toUpperCase();
  976. * const addGreeting = (input: string): string => `Hello, ${input}!`;
  977. *
  978. * const upperCaseLambda = RunnableLambda.from(toUpperCase);
  979. * const greetingLambda = RunnableLambda.from(addGreeting);
  980. *
  981. * const chain = new RunnableEach({
  982. * bound: upperCaseLambda.pipe(greetingLambda),
  983. * });
  984. *
  985. * const result = await chain.invoke(["alice", "bob", "carol"])
  986. *
  987. * // ["Hello, ALICE!", "Hello, BOB!", "Hello, CAROL!"]
  988. * ```
  989. *
  990. * @deprecated This will be removed in the next breaking release.
  991. */
  992. export class RunnableEach extends Runnable {
  993. static lc_name() {
  994. return "RunnableEach";
  995. }
  996. constructor(fields) {
  997. super(fields);
  998. Object.defineProperty(this, "lc_serializable", {
  999. enumerable: true,
  1000. configurable: true,
  1001. writable: true,
  1002. value: true
  1003. });
  1004. Object.defineProperty(this, "lc_namespace", {
  1005. enumerable: true,
  1006. configurable: true,
  1007. writable: true,
  1008. value: ["langchain_core", "runnables"]
  1009. });
  1010. Object.defineProperty(this, "bound", {
  1011. enumerable: true,
  1012. configurable: true,
  1013. writable: true,
  1014. value: void 0
  1015. });
  1016. this.bound = fields.bound;
  1017. }
  1018. /**
  1019. * Binds the runnable with the specified arguments.
  1020. * @param kwargs The arguments to bind the runnable with.
  1021. * @returns A new instance of the `RunnableEach` class that is bound with the specified arguments.
  1022. *
  1023. * @deprecated Use {@link withConfig} instead. This will be removed in the next breaking release.
  1024. */
  1025. bind(kwargs) {
  1026. return new RunnableEach({
  1027. bound: this.bound.bind(kwargs),
  1028. });
  1029. }
  1030. /**
  1031. * Invokes the runnable with the specified input and configuration.
  1032. * @param input The input to invoke the runnable with.
  1033. * @param config The configuration to invoke the runnable with.
  1034. * @returns A promise that resolves to the output of the runnable.
  1035. */
  1036. async invoke(inputs, config) {
  1037. return this._callWithConfig(this._invoke.bind(this), inputs, config);
  1038. }
  1039. /**
  1040. * A helper method that is used to invoke the runnable with the specified input and configuration.
  1041. * @param input The input to invoke the runnable with.
  1042. * @param config The configuration to invoke the runnable with.
  1043. * @returns A promise that resolves to the output of the runnable.
  1044. */
  1045. async _invoke(inputs, config, runManager) {
  1046. return this.bound.batch(inputs, patchConfig(config, { callbacks: runManager?.getChild() }));
  1047. }
  1048. /**
  1049. * Bind lifecycle listeners to a Runnable, returning a new Runnable.
  1050. * The Run object contains information about the run, including its id,
  1051. * type, input, output, error, startTime, endTime, and any tags or metadata
  1052. * added to the run.
  1053. *
  1054. * @param {Object} params - The object containing the callback functions.
  1055. * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object.
  1056. * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object.
  1057. * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object.
  1058. */
  1059. withListeners({ onStart, onEnd, onError, }) {
  1060. return new RunnableEach({
  1061. bound: this.bound.withListeners({ onStart, onEnd, onError }),
  1062. });
  1063. }
  1064. }
  1065. /**
  1066. * Base class for runnables that can be retried a
  1067. * specified number of times.
  1068. * @example
  1069. * ```typescript
  1070. * import {
  1071. * RunnableLambda,
  1072. * RunnableRetry,
  1073. * } from "@langchain/core/runnables";
  1074. *
  1075. * // Simulate an API call that fails
  1076. * const simulateApiCall = (input: string): string => {
  1077. * console.log(`Attempting API call with input: ${input}`);
  1078. * throw new Error("API call failed due to network issue");
  1079. * };
  1080. *
  1081. * const apiCallLambda = RunnableLambda.from(simulateApiCall);
  1082. *
  1083. * // Apply retry logic using the .withRetry() method
  1084. * const apiCallWithRetry = apiCallLambda.withRetry({ stopAfterAttempt: 3 });
  1085. *
  1086. * // Alternatively, create a RunnableRetry instance manually
  1087. * const manualRetry = new RunnableRetry({
  1088. * bound: apiCallLambda,
  1089. * maxAttemptNumber: 3,
  1090. * config: {},
  1091. * });
  1092. *
  1093. * // Example invocation using the .withRetry() method
  1094. * const res = await apiCallWithRetry
  1095. * .invoke("Request 1")
  1096. * .catch((error) => {
  1097. * console.error("Failed after multiple retries:", error.message);
  1098. * });
  1099. *
  1100. * // Example invocation using the manual retry instance
  1101. * const res2 = await manualRetry
  1102. * .invoke("Request 2")
  1103. * .catch((error) => {
  1104. * console.error("Failed after multiple retries:", error.message);
  1105. * });
  1106. * ```
  1107. */
  1108. export class RunnableRetry extends RunnableBinding {
  1109. static lc_name() {
  1110. return "RunnableRetry";
  1111. }
  1112. constructor(fields) {
  1113. super(fields);
  1114. Object.defineProperty(this, "lc_namespace", {
  1115. enumerable: true,
  1116. configurable: true,
  1117. writable: true,
  1118. value: ["langchain_core", "runnables"]
  1119. });
  1120. Object.defineProperty(this, "maxAttemptNumber", {
  1121. enumerable: true,
  1122. configurable: true,
  1123. writable: true,
  1124. value: 3
  1125. });
  1126. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1127. Object.defineProperty(this, "onFailedAttempt", {
  1128. enumerable: true,
  1129. configurable: true,
  1130. writable: true,
  1131. value: () => { }
  1132. });
  1133. this.maxAttemptNumber = fields.maxAttemptNumber ?? this.maxAttemptNumber;
  1134. this.onFailedAttempt = fields.onFailedAttempt ?? this.onFailedAttempt;
  1135. }
  1136. _patchConfigForRetry(attempt, config, runManager) {
  1137. const tag = attempt > 1 ? `retry:attempt:${attempt}` : undefined;
  1138. return patchConfig(config, { callbacks: runManager?.getChild(tag) });
  1139. }
  1140. async _invoke(input, config, runManager) {
  1141. return pRetry((attemptNumber) => super.invoke(input, this._patchConfigForRetry(attemptNumber, config, runManager)), {
  1142. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1143. onFailedAttempt: (error) => this.onFailedAttempt(error, input),
  1144. retries: Math.max(this.maxAttemptNumber - 1, 0),
  1145. randomize: true,
  1146. });
  1147. }
  1148. /**
  1149. * Method that invokes the runnable with the specified input, run manager,
  1150. * and config. It handles the retry logic by catching any errors and
  1151. * recursively invoking itself with the updated config for the next retry
  1152. * attempt.
  1153. * @param input The input for the runnable.
  1154. * @param runManager The run manager for the runnable.
  1155. * @param config The config for the runnable.
  1156. * @returns A promise that resolves to the output of the runnable.
  1157. */
  1158. async invoke(input, config) {
  1159. return this._callWithConfig(this._invoke.bind(this), input, config);
  1160. }
  1161. async _batch(inputs, configs, runManagers, batchOptions) {
  1162. const resultsMap = {};
  1163. try {
  1164. await pRetry(async (attemptNumber) => {
  1165. const remainingIndexes = inputs
  1166. .map((_, i) => i)
  1167. .filter((i) => resultsMap[i.toString()] === undefined ||
  1168. // eslint-disable-next-line no-instanceof/no-instanceof
  1169. resultsMap[i.toString()] instanceof Error);
  1170. const remainingInputs = remainingIndexes.map((i) => inputs[i]);
  1171. const patchedConfigs = remainingIndexes.map((i) => this._patchConfigForRetry(attemptNumber, configs?.[i], runManagers?.[i]));
  1172. const results = await super.batch(remainingInputs, patchedConfigs, {
  1173. ...batchOptions,
  1174. returnExceptions: true,
  1175. });
  1176. let firstException;
  1177. for (let i = 0; i < results.length; i += 1) {
  1178. const result = results[i];
  1179. const resultMapIndex = remainingIndexes[i];
  1180. // eslint-disable-next-line no-instanceof/no-instanceof
  1181. if (result instanceof Error) {
  1182. if (firstException === undefined) {
  1183. firstException = result;
  1184. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1185. firstException.input = remainingInputs[i];
  1186. }
  1187. }
  1188. resultsMap[resultMapIndex.toString()] = result;
  1189. }
  1190. if (firstException) {
  1191. throw firstException;
  1192. }
  1193. return results;
  1194. }, {
  1195. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1196. onFailedAttempt: (error) => this.onFailedAttempt(error, error.input),
  1197. retries: Math.max(this.maxAttemptNumber - 1, 0),
  1198. randomize: true,
  1199. });
  1200. }
  1201. catch (e) {
  1202. if (batchOptions?.returnExceptions !== true) {
  1203. throw e;
  1204. }
  1205. }
  1206. return Object.keys(resultsMap)
  1207. .sort((a, b) => parseInt(a, 10) - parseInt(b, 10))
  1208. .map((key) => resultsMap[parseInt(key, 10)]);
  1209. }
  1210. async batch(inputs, options, batchOptions) {
  1211. return this._batchWithConfig(this._batch.bind(this), inputs, options, batchOptions);
  1212. }
  1213. }
  1214. /**
  1215. * A sequence of runnables, where the output of each is the input of the next.
  1216. * @example
  1217. * ```typescript
  1218. * const promptTemplate = PromptTemplate.fromTemplate(
  1219. * "Tell me a joke about {topic}",
  1220. * );
  1221. * const chain = RunnableSequence.from([promptTemplate, new ChatOpenAI({})]);
  1222. * const result = await chain.invoke({ topic: "bears" });
  1223. * ```
  1224. */
  1225. export class RunnableSequence extends Runnable {
  1226. static lc_name() {
  1227. return "RunnableSequence";
  1228. }
  1229. constructor(fields) {
  1230. super(fields);
  1231. Object.defineProperty(this, "first", {
  1232. enumerable: true,
  1233. configurable: true,
  1234. writable: true,
  1235. value: void 0
  1236. });
  1237. Object.defineProperty(this, "middle", {
  1238. enumerable: true,
  1239. configurable: true,
  1240. writable: true,
  1241. value: []
  1242. });
  1243. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1244. Object.defineProperty(this, "last", {
  1245. enumerable: true,
  1246. configurable: true,
  1247. writable: true,
  1248. value: void 0
  1249. });
  1250. Object.defineProperty(this, "omitSequenceTags", {
  1251. enumerable: true,
  1252. configurable: true,
  1253. writable: true,
  1254. value: false
  1255. });
  1256. Object.defineProperty(this, "lc_serializable", {
  1257. enumerable: true,
  1258. configurable: true,
  1259. writable: true,
  1260. value: true
  1261. });
  1262. Object.defineProperty(this, "lc_namespace", {
  1263. enumerable: true,
  1264. configurable: true,
  1265. writable: true,
  1266. value: ["langchain_core", "runnables"]
  1267. });
  1268. this.first = fields.first;
  1269. this.middle = fields.middle ?? this.middle;
  1270. this.last = fields.last;
  1271. this.name = fields.name;
  1272. this.omitSequenceTags = fields.omitSequenceTags ?? this.omitSequenceTags;
  1273. }
  1274. get steps() {
  1275. return [this.first, ...this.middle, this.last];
  1276. }
  1277. async invoke(input, options) {
  1278. const config = ensureConfig(options);
  1279. const callbackManager_ = await getCallbackManagerForConfig(config);
  1280. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), config.runId, undefined, undefined, undefined, config?.runName);
  1281. delete config.runId;
  1282. let nextStepInput = input;
  1283. let finalOutput;
  1284. try {
  1285. const initialSteps = [this.first, ...this.middle];
  1286. for (let i = 0; i < initialSteps.length; i += 1) {
  1287. const step = initialSteps[i];
  1288. const promise = step.invoke(nextStepInput, patchConfig(config, {
  1289. callbacks: runManager?.getChild(this.omitSequenceTags ? undefined : `seq:step:${i + 1}`),
  1290. }));
  1291. nextStepInput = await raceWithSignal(promise, options?.signal);
  1292. }
  1293. // TypeScript can't detect that the last output of the sequence returns RunOutput, so call it out of the loop here
  1294. if (options?.signal?.aborted) {
  1295. throw new Error("Aborted");
  1296. }
  1297. finalOutput = await this.last.invoke(nextStepInput, patchConfig(config, {
  1298. callbacks: runManager?.getChild(this.omitSequenceTags ? undefined : `seq:step:${this.steps.length}`),
  1299. }));
  1300. }
  1301. catch (e) {
  1302. await runManager?.handleChainError(e);
  1303. throw e;
  1304. }
  1305. await runManager?.handleChainEnd(_coerceToDict(finalOutput, "output"));
  1306. return finalOutput;
  1307. }
  1308. async batch(inputs, options, batchOptions) {
  1309. const configList = this._getOptionsList(options ?? {}, inputs.length);
  1310. const callbackManagers = await Promise.all(configList.map(getCallbackManagerForConfig));
  1311. const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => {
  1312. const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), _coerceToDict(inputs[i], "input"), configList[i].runId, undefined, undefined, undefined, configList[i].runName);
  1313. delete configList[i].runId;
  1314. return handleStartRes;
  1315. }));
  1316. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1317. let nextStepInputs = inputs;
  1318. try {
  1319. for (let i = 0; i < this.steps.length; i += 1) {
  1320. const step = this.steps[i];
  1321. const promise = step.batch(nextStepInputs, runManagers.map((runManager, j) => {
  1322. const childRunManager = runManager?.getChild(this.omitSequenceTags ? undefined : `seq:step:${i + 1}`);
  1323. return patchConfig(configList[j], { callbacks: childRunManager });
  1324. }), batchOptions);
  1325. nextStepInputs = await raceWithSignal(promise, configList[0]?.signal);
  1326. }
  1327. }
  1328. catch (e) {
  1329. await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e)));
  1330. throw e;
  1331. }
  1332. await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(_coerceToDict(nextStepInputs, "output"))));
  1333. return nextStepInputs;
  1334. }
  1335. async *_streamIterator(input, options) {
  1336. const callbackManager_ = await getCallbackManagerForConfig(options);
  1337. const { runId, ...otherOptions } = options ?? {};
  1338. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), runId, undefined, undefined, undefined, otherOptions?.runName);
  1339. const steps = [this.first, ...this.middle, this.last];
  1340. let concatSupported = true;
  1341. let finalOutput;
  1342. async function* inputGenerator() {
  1343. yield input;
  1344. }
  1345. try {
  1346. let finalGenerator = steps[0].transform(inputGenerator(), patchConfig(otherOptions, {
  1347. callbacks: runManager?.getChild(this.omitSequenceTags ? undefined : `seq:step:1`),
  1348. }));
  1349. for (let i = 1; i < steps.length; i += 1) {
  1350. const step = steps[i];
  1351. finalGenerator = await step.transform(finalGenerator, patchConfig(otherOptions, {
  1352. callbacks: runManager?.getChild(this.omitSequenceTags ? undefined : `seq:step:${i + 1}`),
  1353. }));
  1354. }
  1355. for await (const chunk of finalGenerator) {
  1356. options?.signal?.throwIfAborted();
  1357. yield chunk;
  1358. if (concatSupported) {
  1359. if (finalOutput === undefined) {
  1360. finalOutput = chunk;
  1361. }
  1362. else {
  1363. try {
  1364. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1365. finalOutput = concat(finalOutput, chunk);
  1366. }
  1367. catch (e) {
  1368. finalOutput = undefined;
  1369. concatSupported = false;
  1370. }
  1371. }
  1372. }
  1373. }
  1374. }
  1375. catch (e) {
  1376. await runManager?.handleChainError(e);
  1377. throw e;
  1378. }
  1379. await runManager?.handleChainEnd(_coerceToDict(finalOutput, "output"));
  1380. }
  1381. getGraph(config) {
  1382. const graph = new Graph();
  1383. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1384. let currentLastNode = null;
  1385. this.steps.forEach((step, index) => {
  1386. const stepGraph = step.getGraph(config);
  1387. if (index !== 0) {
  1388. stepGraph.trimFirstNode();
  1389. }
  1390. if (index !== this.steps.length - 1) {
  1391. stepGraph.trimLastNode();
  1392. }
  1393. graph.extend(stepGraph);
  1394. const stepFirstNode = stepGraph.firstNode();
  1395. if (!stepFirstNode) {
  1396. throw new Error(`Runnable ${step} has no first node`);
  1397. }
  1398. if (currentLastNode) {
  1399. graph.addEdge(currentLastNode, stepFirstNode);
  1400. }
  1401. currentLastNode = stepGraph.lastNode();
  1402. });
  1403. return graph;
  1404. }
  1405. pipe(coerceable) {
  1406. if (RunnableSequence.isRunnableSequence(coerceable)) {
  1407. return new RunnableSequence({
  1408. first: this.first,
  1409. middle: this.middle.concat([
  1410. this.last,
  1411. coerceable.first,
  1412. ...coerceable.middle,
  1413. ]),
  1414. last: coerceable.last,
  1415. name: this.name ?? coerceable.name,
  1416. });
  1417. }
  1418. else {
  1419. return new RunnableSequence({
  1420. first: this.first,
  1421. middle: [...this.middle, this.last],
  1422. last: _coerceToRunnable(coerceable),
  1423. name: this.name,
  1424. });
  1425. }
  1426. }
  1427. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1428. static isRunnableSequence(thing) {
  1429. return Array.isArray(thing.middle) && Runnable.isRunnable(thing);
  1430. }
  1431. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1432. static from([first, ...runnables], nameOrFields) {
  1433. let extra = {};
  1434. if (typeof nameOrFields === "string") {
  1435. extra.name = nameOrFields;
  1436. }
  1437. else if (nameOrFields !== undefined) {
  1438. extra = nameOrFields;
  1439. }
  1440. return new RunnableSequence({
  1441. ...extra,
  1442. first: _coerceToRunnable(first),
  1443. middle: runnables.slice(0, -1).map(_coerceToRunnable),
  1444. last: _coerceToRunnable(runnables[runnables.length - 1]),
  1445. });
  1446. }
  1447. }
  1448. /**
  1449. * A runnable that runs a mapping of runnables in parallel,
  1450. * and returns a mapping of their outputs.
  1451. * @example
  1452. * ```typescript
  1453. * const mapChain = RunnableMap.from({
  1454. * joke: PromptTemplate.fromTemplate("Tell me a joke about {topic}").pipe(
  1455. * new ChatAnthropic({}),
  1456. * ),
  1457. * poem: PromptTemplate.fromTemplate("write a 2-line poem about {topic}").pipe(
  1458. * new ChatAnthropic({}),
  1459. * ),
  1460. * });
  1461. * const result = await mapChain.invoke({ topic: "bear" });
  1462. * ```
  1463. */
  1464. export class RunnableMap extends Runnable {
  1465. static lc_name() {
  1466. return "RunnableMap";
  1467. }
  1468. getStepsKeys() {
  1469. return Object.keys(this.steps);
  1470. }
  1471. constructor(fields) {
  1472. super(fields);
  1473. Object.defineProperty(this, "lc_namespace", {
  1474. enumerable: true,
  1475. configurable: true,
  1476. writable: true,
  1477. value: ["langchain_core", "runnables"]
  1478. });
  1479. Object.defineProperty(this, "lc_serializable", {
  1480. enumerable: true,
  1481. configurable: true,
  1482. writable: true,
  1483. value: true
  1484. });
  1485. Object.defineProperty(this, "steps", {
  1486. enumerable: true,
  1487. configurable: true,
  1488. writable: true,
  1489. value: void 0
  1490. });
  1491. this.steps = {};
  1492. for (const [key, value] of Object.entries(fields.steps)) {
  1493. this.steps[key] = _coerceToRunnable(value);
  1494. }
  1495. }
  1496. static from(steps) {
  1497. return new RunnableMap({ steps });
  1498. }
  1499. async invoke(input, options) {
  1500. const config = ensureConfig(options);
  1501. const callbackManager_ = await getCallbackManagerForConfig(config);
  1502. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), {
  1503. input,
  1504. }, config.runId, undefined, undefined, undefined, config?.runName);
  1505. delete config.runId;
  1506. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1507. const output = {};
  1508. try {
  1509. const promises = Object.entries(this.steps).map(async ([key, runnable]) => {
  1510. output[key] = await runnable.invoke(input, patchConfig(config, {
  1511. callbacks: runManager?.getChild(`map:key:${key}`),
  1512. }));
  1513. });
  1514. await raceWithSignal(Promise.all(promises), options?.signal);
  1515. }
  1516. catch (e) {
  1517. await runManager?.handleChainError(e);
  1518. throw e;
  1519. }
  1520. await runManager?.handleChainEnd(output);
  1521. return output;
  1522. }
  1523. async *_transform(generator, runManager, options) {
  1524. // shallow copy steps to ignore changes while iterating
  1525. const steps = { ...this.steps };
  1526. // each step gets a copy of the input iterator
  1527. const inputCopies = atee(generator, Object.keys(steps).length);
  1528. // start the first iteration of each output iterator
  1529. const tasks = new Map(Object.entries(steps).map(([key, runnable], i) => {
  1530. const gen = runnable.transform(inputCopies[i], patchConfig(options, {
  1531. callbacks: runManager?.getChild(`map:key:${key}`),
  1532. }));
  1533. return [key, gen.next().then((result) => ({ key, gen, result }))];
  1534. }));
  1535. // yield chunks as they become available,
  1536. // starting new iterations as needed,
  1537. // until all iterators are done
  1538. while (tasks.size) {
  1539. const promise = Promise.race(tasks.values());
  1540. const { key, result, gen } = await raceWithSignal(promise, options?.signal);
  1541. tasks.delete(key);
  1542. if (!result.done) {
  1543. yield { [key]: result.value };
  1544. tasks.set(key, gen.next().then((result) => ({ key, gen, result })));
  1545. }
  1546. }
  1547. }
  1548. transform(generator, options) {
  1549. return this._transformStreamWithConfig(generator, this._transform.bind(this), options);
  1550. }
  1551. async stream(input, options) {
  1552. async function* generator() {
  1553. yield input;
  1554. }
  1555. const config = ensureConfig(options);
  1556. const wrappedGenerator = new AsyncGeneratorWithSetup({
  1557. generator: this.transform(generator(), config),
  1558. config,
  1559. });
  1560. await wrappedGenerator.setup;
  1561. return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
  1562. }
  1563. }
  1564. /**
  1565. * A runnable that wraps a traced LangSmith function.
  1566. */
  1567. export class RunnableTraceable extends Runnable {
  1568. constructor(fields) {
  1569. super(fields);
  1570. Object.defineProperty(this, "lc_serializable", {
  1571. enumerable: true,
  1572. configurable: true,
  1573. writable: true,
  1574. value: false
  1575. });
  1576. Object.defineProperty(this, "lc_namespace", {
  1577. enumerable: true,
  1578. configurable: true,
  1579. writable: true,
  1580. value: ["langchain_core", "runnables"]
  1581. });
  1582. Object.defineProperty(this, "func", {
  1583. enumerable: true,
  1584. configurable: true,
  1585. writable: true,
  1586. value: void 0
  1587. });
  1588. if (!isTraceableFunction(fields.func)) {
  1589. throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function");
  1590. }
  1591. this.func = fields.func;
  1592. }
  1593. async invoke(input, options) {
  1594. const [config] = this._getOptionsList(options ?? {}, 1);
  1595. const callbacks = await getCallbackManagerForConfig(config);
  1596. const promise = this.func(patchConfig(config, { callbacks }), input);
  1597. return raceWithSignal(promise, config?.signal);
  1598. }
  1599. async *_streamIterator(input, options) {
  1600. const [config] = this._getOptionsList(options ?? {}, 1);
  1601. const result = await this.invoke(input, options);
  1602. if (isAsyncIterable(result)) {
  1603. for await (const item of result) {
  1604. config?.signal?.throwIfAborted();
  1605. yield item;
  1606. }
  1607. return;
  1608. }
  1609. if (isIterator(result)) {
  1610. while (true) {
  1611. config?.signal?.throwIfAborted();
  1612. const state = result.next();
  1613. if (state.done)
  1614. break;
  1615. yield state.value;
  1616. }
  1617. return;
  1618. }
  1619. yield result;
  1620. }
  1621. static from(func) {
  1622. return new RunnableTraceable({ func });
  1623. }
  1624. }
  1625. function assertNonTraceableFunction(func) {
  1626. if (isTraceableFunction(func)) {
  1627. throw new Error("RunnableLambda requires a function that is not wrapped in traceable higher-order function. This shouldn't happen.");
  1628. }
  1629. }
  1630. /**
  1631. * A runnable that wraps an arbitrary function that takes a single argument.
  1632. * @example
  1633. * ```typescript
  1634. * import { RunnableLambda } from "@langchain/core/runnables";
  1635. *
  1636. * const add = (input: { x: number; y: number }) => input.x + input.y;
  1637. *
  1638. * const multiply = (input: { value: number; multiplier: number }) =>
  1639. * input.value * input.multiplier;
  1640. *
  1641. * // Create runnables for the functions
  1642. * const addLambda = RunnableLambda.from(add);
  1643. * const multiplyLambda = RunnableLambda.from(multiply);
  1644. *
  1645. * // Chain the lambdas for a mathematical operation
  1646. * const chainedLambda = addLambda.pipe((result) =>
  1647. * multiplyLambda.invoke({ value: result, multiplier: 2 })
  1648. * );
  1649. *
  1650. * // Example invocation of the chainedLambda
  1651. * const result = await chainedLambda.invoke({ x: 2, y: 3 });
  1652. *
  1653. * // Will log "10" (since (2 + 3) * 2 = 10)
  1654. * ```
  1655. */
  1656. export class RunnableLambda extends Runnable {
  1657. static lc_name() {
  1658. return "RunnableLambda";
  1659. }
  1660. constructor(fields) {
  1661. if (isTraceableFunction(fields.func)) {
  1662. // eslint-disable-next-line no-constructor-return
  1663. return RunnableTraceable.from(fields.func);
  1664. }
  1665. super(fields);
  1666. Object.defineProperty(this, "lc_namespace", {
  1667. enumerable: true,
  1668. configurable: true,
  1669. writable: true,
  1670. value: ["langchain_core", "runnables"]
  1671. });
  1672. Object.defineProperty(this, "func", {
  1673. enumerable: true,
  1674. configurable: true,
  1675. writable: true,
  1676. value: void 0
  1677. });
  1678. assertNonTraceableFunction(fields.func);
  1679. this.func = fields.func;
  1680. }
  1681. static from(func) {
  1682. return new RunnableLambda({
  1683. func,
  1684. });
  1685. }
  1686. async _invoke(input, config, runManager) {
  1687. return new Promise((resolve, reject) => {
  1688. const childConfig = patchConfig(config, {
  1689. callbacks: runManager?.getChild(),
  1690. recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1,
  1691. });
  1692. void AsyncLocalStorageProviderSingleton.runWithConfig(pickRunnableConfigKeys(childConfig), async () => {
  1693. try {
  1694. let output = await this.func(input, {
  1695. ...childConfig,
  1696. });
  1697. if (output && Runnable.isRunnable(output)) {
  1698. if (config?.recursionLimit === 0) {
  1699. throw new Error("Recursion limit reached.");
  1700. }
  1701. output = await output.invoke(input, {
  1702. ...childConfig,
  1703. recursionLimit: (childConfig.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1,
  1704. });
  1705. }
  1706. else if (isAsyncIterable(output)) {
  1707. let finalOutput;
  1708. for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) {
  1709. config?.signal?.throwIfAborted();
  1710. if (finalOutput === undefined) {
  1711. finalOutput = chunk;
  1712. }
  1713. else {
  1714. // Make a best effort to gather, for any type that supports concat.
  1715. try {
  1716. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1717. finalOutput = concat(finalOutput, chunk);
  1718. }
  1719. catch (e) {
  1720. finalOutput = chunk;
  1721. }
  1722. }
  1723. }
  1724. output = finalOutput;
  1725. }
  1726. else if (isIterableIterator(output)) {
  1727. let finalOutput;
  1728. for (const chunk of consumeIteratorInContext(childConfig, output)) {
  1729. config?.signal?.throwIfAborted();
  1730. if (finalOutput === undefined) {
  1731. finalOutput = chunk;
  1732. }
  1733. else {
  1734. // Make a best effort to gather, for any type that supports concat.
  1735. try {
  1736. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1737. finalOutput = concat(finalOutput, chunk);
  1738. }
  1739. catch (e) {
  1740. finalOutput = chunk;
  1741. }
  1742. }
  1743. }
  1744. output = finalOutput;
  1745. }
  1746. resolve(output);
  1747. }
  1748. catch (e) {
  1749. reject(e);
  1750. }
  1751. });
  1752. });
  1753. }
  1754. async invoke(input, options) {
  1755. return this._callWithConfig(this._invoke.bind(this), input, options);
  1756. }
  1757. async *_transform(generator, runManager, config) {
  1758. let finalChunk;
  1759. for await (const chunk of generator) {
  1760. if (finalChunk === undefined) {
  1761. finalChunk = chunk;
  1762. }
  1763. else {
  1764. // Make a best effort to gather, for any type that supports concat.
  1765. try {
  1766. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  1767. finalChunk = concat(finalChunk, chunk);
  1768. }
  1769. catch (e) {
  1770. finalChunk = chunk;
  1771. }
  1772. }
  1773. }
  1774. const childConfig = patchConfig(config, {
  1775. callbacks: runManager?.getChild(),
  1776. recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1,
  1777. });
  1778. const output = await new Promise((resolve, reject) => {
  1779. void AsyncLocalStorageProviderSingleton.runWithConfig(pickRunnableConfigKeys(childConfig), async () => {
  1780. try {
  1781. const res = await this.func(finalChunk, {
  1782. ...childConfig,
  1783. config: childConfig,
  1784. });
  1785. resolve(res);
  1786. }
  1787. catch (e) {
  1788. reject(e);
  1789. }
  1790. });
  1791. });
  1792. if (output && Runnable.isRunnable(output)) {
  1793. if (config?.recursionLimit === 0) {
  1794. throw new Error("Recursion limit reached.");
  1795. }
  1796. const stream = await output.stream(finalChunk, childConfig);
  1797. for await (const chunk of stream) {
  1798. yield chunk;
  1799. }
  1800. }
  1801. else if (isAsyncIterable(output)) {
  1802. for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) {
  1803. config?.signal?.throwIfAborted();
  1804. yield chunk;
  1805. }
  1806. }
  1807. else if (isIterableIterator(output)) {
  1808. for (const chunk of consumeIteratorInContext(childConfig, output)) {
  1809. config?.signal?.throwIfAborted();
  1810. yield chunk;
  1811. }
  1812. }
  1813. else {
  1814. yield output;
  1815. }
  1816. }
  1817. transform(generator, options) {
  1818. return this._transformStreamWithConfig(generator, this._transform.bind(this), options);
  1819. }
  1820. async stream(input, options) {
  1821. async function* generator() {
  1822. yield input;
  1823. }
  1824. const config = ensureConfig(options);
  1825. const wrappedGenerator = new AsyncGeneratorWithSetup({
  1826. generator: this.transform(generator(), config),
  1827. config,
  1828. });
  1829. await wrappedGenerator.setup;
  1830. return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
  1831. }
  1832. }
  1833. /**
  1834. * A runnable that runs a mapping of runnables in parallel,
  1835. * and returns a mapping of their outputs.
  1836. * @example
  1837. * ```typescript
  1838. * import {
  1839. * RunnableLambda,
  1840. * RunnableParallel,
  1841. * } from "@langchain/core/runnables";
  1842. *
  1843. * const addYears = (age: number): number => age + 5;
  1844. * const yearsToFifty = (age: number): number => 50 - age;
  1845. * const yearsToHundred = (age: number): number => 100 - age;
  1846. *
  1847. * const addYearsLambda = RunnableLambda.from(addYears);
  1848. * const milestoneFiftyLambda = RunnableLambda.from(yearsToFifty);
  1849. * const milestoneHundredLambda = RunnableLambda.from(yearsToHundred);
  1850. *
  1851. * // Pipe will coerce objects into RunnableParallel by default, but we
  1852. * // explicitly instantiate one here to demonstrate
  1853. * const sequence = addYearsLambda.pipe(
  1854. * RunnableParallel.from({
  1855. * years_to_fifty: milestoneFiftyLambda,
  1856. * years_to_hundred: milestoneHundredLambda,
  1857. * })
  1858. * );
  1859. *
  1860. * // Invoke the sequence with a single age input
  1861. * const res = sequence.invoke(25);
  1862. *
  1863. * // { years_to_fifty: 25, years_to_hundred: 75 }
  1864. * ```
  1865. */
  1866. export class RunnableParallel extends RunnableMap {
  1867. }
  1868. /**
  1869. * A Runnable that can fallback to other Runnables if it fails.
  1870. * External APIs (e.g., APIs for a language model) may at times experience
  1871. * degraded performance or even downtime.
  1872. *
  1873. * In these cases, it can be useful to have a fallback Runnable that can be
  1874. * used in place of the original Runnable (e.g., fallback to another LLM provider).
  1875. *
  1876. * Fallbacks can be defined at the level of a single Runnable, or at the level
  1877. * of a chain of Runnables. Fallbacks are tried in order until one succeeds or
  1878. * all fail.
  1879. *
  1880. * While you can instantiate a `RunnableWithFallbacks` directly, it is usually
  1881. * more convenient to use the `withFallbacks` method on an existing Runnable.
  1882. *
  1883. * When streaming, fallbacks will only be called on failures during the initial
  1884. * stream creation. Errors that occur after a stream starts will not fallback
  1885. * to the next Runnable.
  1886. *
  1887. * @example
  1888. * ```typescript
  1889. * import {
  1890. * RunnableLambda,
  1891. * RunnableWithFallbacks,
  1892. * } from "@langchain/core/runnables";
  1893. *
  1894. * const primaryOperation = (input: string): string => {
  1895. * if (input !== "safe") {
  1896. * throw new Error("Primary operation failed due to unsafe input");
  1897. * }
  1898. * return `Processed: ${input}`;
  1899. * };
  1900. *
  1901. * // Define a fallback operation that processes the input differently
  1902. * const fallbackOperation = (input: string): string =>
  1903. * `Fallback processed: ${input}`;
  1904. *
  1905. * const primaryRunnable = RunnableLambda.from(primaryOperation);
  1906. * const fallbackRunnable = RunnableLambda.from(fallbackOperation);
  1907. *
  1908. * // Apply the fallback logic using the .withFallbacks() method
  1909. * const runnableWithFallback = primaryRunnable.withFallbacks([fallbackRunnable]);
  1910. *
  1911. * // Alternatively, create a RunnableWithFallbacks instance manually
  1912. * const manualFallbackChain = new RunnableWithFallbacks({
  1913. * runnable: primaryRunnable,
  1914. * fallbacks: [fallbackRunnable],
  1915. * });
  1916. *
  1917. * // Example invocation using .withFallbacks()
  1918. * const res = await runnableWithFallback
  1919. * .invoke("unsafe input")
  1920. * .catch((error) => {
  1921. * console.error("Failed after all attempts:", error.message);
  1922. * });
  1923. *
  1924. * // "Fallback processed: unsafe input"
  1925. *
  1926. * // Example invocation using manual instantiation
  1927. * const res = await manualFallbackChain
  1928. * .invoke("safe")
  1929. * .catch((error) => {
  1930. * console.error("Failed after all attempts:", error.message);
  1931. * });
  1932. *
  1933. * // "Processed: safe"
  1934. * ```
  1935. */
  1936. export class RunnableWithFallbacks extends Runnable {
  1937. static lc_name() {
  1938. return "RunnableWithFallbacks";
  1939. }
  1940. constructor(fields) {
  1941. super(fields);
  1942. Object.defineProperty(this, "lc_namespace", {
  1943. enumerable: true,
  1944. configurable: true,
  1945. writable: true,
  1946. value: ["langchain_core", "runnables"]
  1947. });
  1948. Object.defineProperty(this, "lc_serializable", {
  1949. enumerable: true,
  1950. configurable: true,
  1951. writable: true,
  1952. value: true
  1953. });
  1954. Object.defineProperty(this, "runnable", {
  1955. enumerable: true,
  1956. configurable: true,
  1957. writable: true,
  1958. value: void 0
  1959. });
  1960. Object.defineProperty(this, "fallbacks", {
  1961. enumerable: true,
  1962. configurable: true,
  1963. writable: true,
  1964. value: void 0
  1965. });
  1966. this.runnable = fields.runnable;
  1967. this.fallbacks = fields.fallbacks;
  1968. }
  1969. *runnables() {
  1970. yield this.runnable;
  1971. for (const fallback of this.fallbacks) {
  1972. yield fallback;
  1973. }
  1974. }
  1975. async invoke(input, options) {
  1976. const config = ensureConfig(options);
  1977. const callbackManager_ = await getCallbackManagerForConfig(config);
  1978. const { runId, ...otherConfigFields } = config;
  1979. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), runId, undefined, undefined, undefined, otherConfigFields?.runName);
  1980. const childConfig = patchConfig(otherConfigFields, {
  1981. callbacks: runManager?.getChild(),
  1982. });
  1983. const res = await AsyncLocalStorageProviderSingleton.runWithConfig(childConfig, async () => {
  1984. let firstError;
  1985. for (const runnable of this.runnables()) {
  1986. config?.signal?.throwIfAborted();
  1987. try {
  1988. const output = await runnable.invoke(input, childConfig);
  1989. await runManager?.handleChainEnd(_coerceToDict(output, "output"));
  1990. return output;
  1991. }
  1992. catch (e) {
  1993. if (firstError === undefined) {
  1994. firstError = e;
  1995. }
  1996. }
  1997. }
  1998. if (firstError === undefined) {
  1999. throw new Error("No error stored at end of fallback.");
  2000. }
  2001. await runManager?.handleChainError(firstError);
  2002. throw firstError;
  2003. });
  2004. return res;
  2005. }
  2006. async *_streamIterator(input, options) {
  2007. const config = ensureConfig(options);
  2008. const callbackManager_ = await getCallbackManagerForConfig(config);
  2009. const { runId, ...otherConfigFields } = config;
  2010. const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), runId, undefined, undefined, undefined, otherConfigFields?.runName);
  2011. let firstError;
  2012. let stream;
  2013. for (const runnable of this.runnables()) {
  2014. config?.signal?.throwIfAborted();
  2015. const childConfig = patchConfig(otherConfigFields, {
  2016. callbacks: runManager?.getChild(),
  2017. });
  2018. try {
  2019. const originalStream = await runnable.stream(input, childConfig);
  2020. stream = consumeAsyncIterableInContext(childConfig, originalStream);
  2021. break;
  2022. }
  2023. catch (e) {
  2024. if (firstError === undefined) {
  2025. firstError = e;
  2026. }
  2027. }
  2028. }
  2029. if (stream === undefined) {
  2030. const error = firstError ?? new Error("No error stored at end of fallback.");
  2031. await runManager?.handleChainError(error);
  2032. throw error;
  2033. }
  2034. let output;
  2035. try {
  2036. for await (const chunk of stream) {
  2037. yield chunk;
  2038. try {
  2039. output = output === undefined ? output : concat(output, chunk);
  2040. }
  2041. catch (e) {
  2042. output = undefined;
  2043. }
  2044. }
  2045. }
  2046. catch (e) {
  2047. await runManager?.handleChainError(e);
  2048. throw e;
  2049. }
  2050. await runManager?.handleChainEnd(_coerceToDict(output, "output"));
  2051. }
  2052. async batch(inputs, options, batchOptions) {
  2053. if (batchOptions?.returnExceptions) {
  2054. throw new Error("Not implemented.");
  2055. }
  2056. const configList = this._getOptionsList(options ?? {}, inputs.length);
  2057. const callbackManagers = await Promise.all(configList.map((config) => getCallbackManagerForConfig(config)));
  2058. const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => {
  2059. const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), _coerceToDict(inputs[i], "input"), configList[i].runId, undefined, undefined, undefined, configList[i].runName);
  2060. delete configList[i].runId;
  2061. return handleStartRes;
  2062. }));
  2063. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  2064. let firstError;
  2065. for (const runnable of this.runnables()) {
  2066. configList[0].signal?.throwIfAborted();
  2067. try {
  2068. const outputs = await runnable.batch(inputs, runManagers.map((runManager, j) => patchConfig(configList[j], {
  2069. callbacks: runManager?.getChild(),
  2070. })), batchOptions);
  2071. await Promise.all(runManagers.map((runManager, i) => runManager?.handleChainEnd(_coerceToDict(outputs[i], "output"))));
  2072. return outputs;
  2073. }
  2074. catch (e) {
  2075. if (firstError === undefined) {
  2076. firstError = e;
  2077. }
  2078. }
  2079. }
  2080. if (!firstError) {
  2081. throw new Error("No error stored at end of fallbacks.");
  2082. }
  2083. await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(firstError)));
  2084. throw firstError;
  2085. }
  2086. }
  2087. // TODO: Figure out why the compiler needs help eliminating Error as a RunOutput type
  2088. export function _coerceToRunnable(coerceable) {
  2089. if (typeof coerceable === "function") {
  2090. return new RunnableLambda({ func: coerceable });
  2091. }
  2092. else if (Runnable.isRunnable(coerceable)) {
  2093. return coerceable;
  2094. }
  2095. else if (!Array.isArray(coerceable) && typeof coerceable === "object") {
  2096. const runnables = {};
  2097. for (const [key, value] of Object.entries(coerceable)) {
  2098. runnables[key] = _coerceToRunnable(value);
  2099. }
  2100. return new RunnableMap({
  2101. steps: runnables,
  2102. });
  2103. }
  2104. else {
  2105. throw new Error(`Expected a Runnable, function or object.\nInstead got an unsupported type.`);
  2106. }
  2107. }
  2108. /**
  2109. * A runnable that assigns key-value pairs to inputs of type `Record<string, unknown>`.
  2110. * @example
  2111. * ```typescript
  2112. * import {
  2113. * RunnableAssign,
  2114. * RunnableLambda,
  2115. * RunnableParallel,
  2116. * } from "@langchain/core/runnables";
  2117. *
  2118. * const calculateAge = (x: { birthYear: number }): { age: number } => {
  2119. * const currentYear = new Date().getFullYear();
  2120. * return { age: currentYear - x.birthYear };
  2121. * };
  2122. *
  2123. * const createGreeting = (x: { name: string }): { greeting: string } => {
  2124. * return { greeting: `Hello, ${x.name}!` };
  2125. * };
  2126. *
  2127. * const mapper = RunnableParallel.from({
  2128. * age_step: RunnableLambda.from(calculateAge),
  2129. * greeting_step: RunnableLambda.from(createGreeting),
  2130. * });
  2131. *
  2132. * const runnableAssign = new RunnableAssign({ mapper });
  2133. *
  2134. * const res = await runnableAssign.invoke({ name: "Alice", birthYear: 1990 });
  2135. *
  2136. * // { name: "Alice", birthYear: 1990, age_step: { age: 34 }, greeting_step: { greeting: "Hello, Alice!" } }
  2137. * ```
  2138. */
  2139. export class RunnableAssign extends Runnable {
  2140. static lc_name() {
  2141. return "RunnableAssign";
  2142. }
  2143. constructor(fields) {
  2144. // eslint-disable-next-line no-instanceof/no-instanceof
  2145. if (fields instanceof RunnableMap) {
  2146. // eslint-disable-next-line no-param-reassign
  2147. fields = { mapper: fields };
  2148. }
  2149. super(fields);
  2150. Object.defineProperty(this, "lc_namespace", {
  2151. enumerable: true,
  2152. configurable: true,
  2153. writable: true,
  2154. value: ["langchain_core", "runnables"]
  2155. });
  2156. Object.defineProperty(this, "lc_serializable", {
  2157. enumerable: true,
  2158. configurable: true,
  2159. writable: true,
  2160. value: true
  2161. });
  2162. Object.defineProperty(this, "mapper", {
  2163. enumerable: true,
  2164. configurable: true,
  2165. writable: true,
  2166. value: void 0
  2167. });
  2168. this.mapper = fields.mapper;
  2169. }
  2170. async invoke(input, options) {
  2171. const mapperResult = await this.mapper.invoke(input, options);
  2172. return {
  2173. ...input,
  2174. ...mapperResult,
  2175. };
  2176. }
  2177. async *_transform(generator, runManager, options) {
  2178. // collect mapper keys
  2179. const mapperKeys = this.mapper.getStepsKeys();
  2180. // create two input gens, one for the mapper, one for the input
  2181. const [forPassthrough, forMapper] = atee(generator);
  2182. // create mapper output gen
  2183. const mapperOutput = this.mapper.transform(forMapper, patchConfig(options, { callbacks: runManager?.getChild() }));
  2184. // start the mapper
  2185. const firstMapperChunkPromise = mapperOutput.next();
  2186. // yield the passthrough
  2187. for await (const chunk of forPassthrough) {
  2188. if (typeof chunk !== "object" || Array.isArray(chunk)) {
  2189. throw new Error(`RunnableAssign can only be used with objects as input, got ${typeof chunk}`);
  2190. }
  2191. const filtered = Object.fromEntries(Object.entries(chunk).filter(([key]) => !mapperKeys.includes(key)));
  2192. if (Object.keys(filtered).length > 0) {
  2193. yield filtered;
  2194. }
  2195. }
  2196. // yield the mapper output
  2197. yield (await firstMapperChunkPromise).value;
  2198. for await (const chunk of mapperOutput) {
  2199. yield chunk;
  2200. }
  2201. }
  2202. transform(generator, options) {
  2203. return this._transformStreamWithConfig(generator, this._transform.bind(this), options);
  2204. }
  2205. async stream(input, options) {
  2206. async function* generator() {
  2207. yield input;
  2208. }
  2209. const config = ensureConfig(options);
  2210. const wrappedGenerator = new AsyncGeneratorWithSetup({
  2211. generator: this.transform(generator(), config),
  2212. config,
  2213. });
  2214. await wrappedGenerator.setup;
  2215. return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
  2216. }
  2217. }
  2218. /**
  2219. * A runnable that assigns key-value pairs to inputs of type `Record<string, unknown>`.
  2220. * Useful for streaming, can be automatically created and chained by calling `runnable.pick();`.
  2221. * @example
  2222. * ```typescript
  2223. * import { RunnablePick } from "@langchain/core/runnables";
  2224. *
  2225. * const inputData = {
  2226. * name: "John",
  2227. * age: 30,
  2228. * city: "New York",
  2229. * country: "USA",
  2230. * email: "john.doe@example.com",
  2231. * phone: "+1234567890",
  2232. * };
  2233. *
  2234. * const basicInfoRunnable = new RunnablePick(["name", "city"]);
  2235. *
  2236. * // Example invocation
  2237. * const res = await basicInfoRunnable.invoke(inputData);
  2238. *
  2239. * // { name: 'John', city: 'New York' }
  2240. * ```
  2241. */
  2242. export class RunnablePick extends Runnable {
  2243. static lc_name() {
  2244. return "RunnablePick";
  2245. }
  2246. constructor(fields) {
  2247. if (typeof fields === "string" || Array.isArray(fields)) {
  2248. // eslint-disable-next-line no-param-reassign
  2249. fields = { keys: fields };
  2250. }
  2251. super(fields);
  2252. Object.defineProperty(this, "lc_namespace", {
  2253. enumerable: true,
  2254. configurable: true,
  2255. writable: true,
  2256. value: ["langchain_core", "runnables"]
  2257. });
  2258. Object.defineProperty(this, "lc_serializable", {
  2259. enumerable: true,
  2260. configurable: true,
  2261. writable: true,
  2262. value: true
  2263. });
  2264. Object.defineProperty(this, "keys", {
  2265. enumerable: true,
  2266. configurable: true,
  2267. writable: true,
  2268. value: void 0
  2269. });
  2270. this.keys = fields.keys;
  2271. }
  2272. async _pick(input) {
  2273. if (typeof this.keys === "string") {
  2274. return input[this.keys];
  2275. }
  2276. else {
  2277. const picked = this.keys
  2278. .map((key) => [key, input[key]])
  2279. .filter((v) => v[1] !== undefined);
  2280. return picked.length === 0 ? undefined : Object.fromEntries(picked);
  2281. }
  2282. }
  2283. async invoke(input, options) {
  2284. return this._callWithConfig(this._pick.bind(this), input, options);
  2285. }
  2286. async *_transform(generator) {
  2287. for await (const chunk of generator) {
  2288. const picked = await this._pick(chunk);
  2289. if (picked !== undefined) {
  2290. yield picked;
  2291. }
  2292. }
  2293. }
  2294. transform(generator, options) {
  2295. return this._transformStreamWithConfig(generator, this._transform.bind(this), options);
  2296. }
  2297. async stream(input, options) {
  2298. async function* generator() {
  2299. yield input;
  2300. }
  2301. const config = ensureConfig(options);
  2302. const wrappedGenerator = new AsyncGeneratorWithSetup({
  2303. generator: this.transform(generator(), config),
  2304. config,
  2305. });
  2306. await wrappedGenerator.setup;
  2307. return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
  2308. }
  2309. }
  2310. export class RunnableToolLike extends RunnableBinding {
  2311. constructor(fields) {
  2312. const sequence = RunnableSequence.from([
  2313. RunnableLambda.from(async (input) => {
  2314. let toolInput;
  2315. if (_isToolCall(input)) {
  2316. try {
  2317. toolInput = await this.schema.parseAsync(input.args);
  2318. }
  2319. catch (e) {
  2320. throw new ToolInputParsingException(`Received tool input did not match expected schema`, JSON.stringify(input.args));
  2321. }
  2322. }
  2323. else {
  2324. toolInput = input;
  2325. }
  2326. return toolInput;
  2327. }).withConfig({ runName: `${fields.name}:parse_input` }),
  2328. fields.bound,
  2329. ]).withConfig({ runName: fields.name });
  2330. super({
  2331. bound: sequence,
  2332. config: fields.config ?? {},
  2333. });
  2334. Object.defineProperty(this, "name", {
  2335. enumerable: true,
  2336. configurable: true,
  2337. writable: true,
  2338. value: void 0
  2339. });
  2340. Object.defineProperty(this, "description", {
  2341. enumerable: true,
  2342. configurable: true,
  2343. writable: true,
  2344. value: void 0
  2345. });
  2346. Object.defineProperty(this, "schema", {
  2347. enumerable: true,
  2348. configurable: true,
  2349. writable: true,
  2350. value: void 0
  2351. });
  2352. this.name = fields.name;
  2353. this.description = fields.description;
  2354. this.schema = fields.schema;
  2355. }
  2356. static lc_name() {
  2357. return "RunnableToolLike";
  2358. }
  2359. }
  2360. /**
  2361. * Given a runnable and a Zod schema, convert the runnable to a tool.
  2362. *
  2363. * @template RunInput The input type for the runnable.
  2364. * @template RunOutput The output type for the runnable.
  2365. *
  2366. * @param {Runnable<RunInput, RunOutput>} runnable The runnable to convert to a tool.
  2367. * @param fields
  2368. * @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable.
  2369. * @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided.
  2370. * @param {z.ZodType<RunInput>} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable.
  2371. * @returns {RunnableToolLike<z.ZodType<RunInput>, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool.
  2372. */
  2373. export function convertRunnableToTool(runnable, fields) {
  2374. const name = fields.name ?? runnable.getName();
  2375. const description = fields.description ?? fields.schema?.description;
  2376. if (fields.schema.constructor === z.ZodString) {
  2377. return new RunnableToolLike({
  2378. name,
  2379. description,
  2380. schema: z
  2381. .object({
  2382. input: z.string(),
  2383. })
  2384. .transform((input) => input.input),
  2385. bound: runnable,
  2386. });
  2387. }
  2388. return new RunnableToolLike({
  2389. name,
  2390. description,
  2391. schema: fields.schema,
  2392. bound: runnable,
  2393. });
  2394. }