agsamantha/node_modules/langsmith/dist/langchain.js

135 lines
5.2 KiB
JavaScript
Raw Normal View History

2024-10-02 15:15:21 -05:00
// These `@langchain/core` imports are intentionally not peer dependencies
// to avoid package manager issues around circular dependencies.
// eslint-disable-next-line import/no-extraneous-dependencies
import { CallbackManager } from "@langchain/core/callbacks/manager";
// eslint-disable-next-line import/no-extraneous-dependencies
import { LangChainTracer } from "@langchain/core/tracers/tracer_langchain";
// eslint-disable-next-line import/no-extraneous-dependencies
import { Runnable, patchConfig, getCallbackManagerForConfig, } from "@langchain/core/runnables";
import { getCurrentRunTree, isTraceableFunction, } from "./traceable.js";
import { isAsyncIterable, isIteratorLike } from "./utils/asserts.js";
/**
* Converts the current run tree active within a traceable-wrapped function
* into a LangChain compatible callback manager. This is useful to handoff tracing
* from LangSmith to LangChain Runnables and LLMs.
*
* @param {RunTree | undefined} currentRunTree Current RunTree from within a traceable-wrapped function. If not provided, the current run tree will be inferred from AsyncLocalStorage.
* @returns {CallbackManager | undefined} Callback manager used by LangChain Runnable objects.
*/
export async function getLangchainCallbacks(currentRunTree) {
const runTree = currentRunTree ?? getCurrentRunTree();
if (!runTree)
return undefined;
// TODO: CallbackManager.configure() is only async due to LangChainTracer
// factory being unnecessarily async.
let callbacks = await CallbackManager.configure();
if (!callbacks && runTree.tracingEnabled) {
callbacks = new CallbackManager();
}
let langChainTracer = callbacks?.handlers.find((handler) => handler?.name === "langchain_tracer");
if (!langChainTracer && runTree.tracingEnabled) {
langChainTracer = new LangChainTracer();
callbacks?.addHandler(langChainTracer);
}
const runMap = new Map();
// find upward root run
let rootRun = runTree;
const rootVisited = new Set();
while (rootRun.parent_run) {
if (rootVisited.has(rootRun.id))
break;
rootVisited.add(rootRun.id);
rootRun = rootRun.parent_run;
}
const queue = [rootRun];
const visited = new Set();
while (queue.length > 0) {
const current = queue.shift();
if (!current || visited.has(current.id))
continue;
visited.add(current.id);
runMap.set(current.id, current);
if (current.child_runs) {
queue.push(...current.child_runs);
}
}
if (callbacks != null) {
Object.assign(callbacks, { _parentRunId: runTree.id });
}
if (langChainTracer != null) {
if ("updateFromRunTree" in langChainTracer &&
typeof langChainTracer === "function") {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore @langchain/core can use a different version of LangSmith
langChainTracer.updateFromRunTree(runTree);
}
else {
Object.assign(langChainTracer, {
runMap,
client: runTree.client,
projectName: runTree.project_name || langChainTracer.projectName,
exampleId: runTree.reference_example_id || langChainTracer.exampleId,
});
}
}
return callbacks;
}
/**
* RunnableTraceable is a Runnable that wraps a traceable function.
* This allows adding Langsmith traced functions into LangChain sequences.
*/
export class RunnableTraceable extends Runnable {
constructor(fields) {
super(fields);
Object.defineProperty(this, "lc_serializable", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "lc_namespace", {
enumerable: true,
configurable: true,
writable: true,
value: ["langchain_core", "runnables"]
});
Object.defineProperty(this, "func", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
if (!isTraceableFunction(fields.func)) {
throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function");
}
this.func = fields.func;
}
async invoke(input, options) {
const [config] = this._getOptionsList(options ?? {}, 1);
const callbacks = await getCallbackManagerForConfig(config);
return (await this.func(patchConfig(config, { callbacks }), input));
}
async *_streamIterator(input, options) {
const result = await this.invoke(input, options);
if (isAsyncIterable(result)) {
for await (const item of result) {
yield item;
}
return;
}
if (isIteratorLike(result)) {
while (true) {
const state = result.next();
if (state.done)
break;
yield state.value;
}
return;
}
yield result;
}
static from(func) {
return new RunnableTraceable({ func });
}
}